@momo-kits/native-kits 0.0.1-beta.4 → 0.0.2-alpha.1

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 (296) hide show
  1. package/CLAUDE.md +99 -0
  2. package/PUBLISH_GUIDE.md +675 -0
  3. package/README.md +184 -5
  4. package/ios/Application/ApplicationEnvironment.swift +71 -0
  5. package/ios/Application/Components.swift +270 -0
  6. package/ios/Application/ComposeApi.swift +22 -0
  7. package/ios/Application/FloatingButton.swift +174 -0
  8. package/ios/Application/HeaderRight.swift +306 -0
  9. package/ios/Application/LanguageSource.swift +93 -0
  10. package/ios/Application/Localize.swift +378 -0
  11. package/ios/Application/LocalizeModifier.swift +30 -0
  12. package/ios/Application/MaxApi.swift +18 -0
  13. package/ios/Application/Navigation/BottomTab/BottomTab.swift +104 -0
  14. package/ios/Application/Navigation/BottomTab/BottomTabBar.swift +215 -0
  15. package/ios/Application/Navigation/BottomTab/CurvedContainer.swift +65 -0
  16. package/ios/Application/Navigation/HeaderBackProps.swift +66 -0
  17. package/ios/Application/Navigation/HeaderTitle.swift +57 -0
  18. package/ios/Application/Navigation/HeaderUser.swift +209 -0
  19. package/ios/Application/Navigation/NavigationContainer.swift +213 -0
  20. package/ios/Application/Navigation/NavigationOptions.swift +109 -0
  21. package/ios/Application/Navigation/Navigator.swift +453 -0
  22. package/ios/Application/Navigation/NavigatorManager.swift +22 -0
  23. package/ios/Application/Navigation/Overplay/BottomSheet.swift +256 -0
  24. package/ios/Application/Navigation/Overplay/ModalScreen.swift +74 -0
  25. package/ios/Application/Navigation/Overplay/SnackBar.swift +144 -0
  26. package/ios/Application/Navigation/Tracking/ScreenTracker.swift +117 -0
  27. package/ios/Application/Navigation/component/Header.swift +178 -0
  28. package/ios/Application/Navigation/component/HeaderBackground.swift +83 -0
  29. package/ios/Application/Navigation/component/HeaderColor.swift +65 -0
  30. package/ios/Application/Navigation/component/HeaderRightWidthKey.swift +11 -0
  31. package/ios/Application/Navigation/component/NavigationFooter.swift +90 -0
  32. package/ios/Application/Navigation/component/NavigationHeaderRight.swift +196 -0
  33. package/ios/Application/Screen.swift +250 -0
  34. package/ios/Application/StackScreen.swift +492 -0
  35. package/ios/Avatar/Avatar.swift +193 -0
  36. package/ios/Badge/Badge.swift +84 -0
  37. package/ios/Badge/BadgeDot.swift +31 -0
  38. package/ios/Badge/BadgeRibbon.swift +319 -0
  39. package/ios/BaselineView/BaselineView.swift +163 -0
  40. package/ios/Button/Button.swift +232 -84
  41. package/ios/CalculatorKeyboard/CalculatorKeyboard.swift +126 -0
  42. package/ios/Carousel/Carousel.swift +196 -0
  43. package/ios/Checkbox/Checkbox.swift +77 -0
  44. package/ios/Chip/Chip.swift +120 -0
  45. package/ios/Collapse/Collapse.swift +192 -0
  46. package/ios/{Colors+Spacing → Colors+Radius+Spacing}/Colors.swift +42 -37
  47. package/ios/Colors+Radius+Spacing/Radius.swift +22 -0
  48. package/ios/{Colors+Spacing → Colors+Radius+Spacing}/Spacing.swift +3 -1
  49. package/ios/Colors+Radius+Spacing/Theme.swift +295 -0
  50. package/ios/DateTimePicker/DateTimePicker.swift +212 -0
  51. package/ios/DateTimePicker/DateTimePickerTypes.swift +55 -0
  52. package/ios/DateTimePicker/DateTimePickerUtils.swift +167 -0
  53. package/ios/DateTimePicker/WheelPicker.swift +165 -0
  54. package/ios/Divider/Divider.swift +16 -0
  55. package/ios/Extensions/ActiveOpacityButtonStyle.swift +14 -0
  56. package/ios/Extensions/Color++.swift +32 -0
  57. package/ios/Icon/Icon.swift +69 -0
  58. package/ios/IconButton/IconButton.swift +140 -0
  59. package/ios/Image/Image.swift +87 -0
  60. package/ios/Information/Information.swift +156 -0
  61. package/ios/Input/ErrorView.swift +58 -0
  62. package/ios/Input/Input.swift +461 -77
  63. package/ios/Input/InputPhoneNumber.swift +192 -0
  64. package/ios/Input/InputSearch.swift +301 -0
  65. package/ios/Input/InputTextArea.swift +318 -0
  66. package/ios/InputDropDown/InputDropDown.swift +201 -0
  67. package/ios/InputMoney/InputMoney.swift +405 -0
  68. package/ios/InputOTP/InputOTP.swift +211 -0
  69. package/ios/Layout/GridContext.swift +30 -0
  70. package/ios/Layout/Item.swift +42 -0
  71. package/ios/Layout/Section.swift +134 -0
  72. package/ios/Loader/Loader.swift +113 -0
  73. package/ios/Lottie/LottieView.swift +86 -0
  74. package/ios/MoMoUIKits.podspec +5 -0
  75. package/ios/OTPKeyboard/KeyboardButton.swift +13 -5
  76. package/ios/OTPKeyboard/OTPKeyboard.swift +1 -1
  77. package/ios/Pagination/PaginationDot.swift +61 -0
  78. package/ios/Pagination/PaginationNumber.swift +35 -0
  79. package/ios/Pagination/PaginationScroll.swift +101 -0
  80. package/ios/Pagination/PaginationWhiteDot.swift +37 -0
  81. package/ios/Popup/PopupDisplay.swift +279 -0
  82. package/ios/Popup/PopupInput.swift +92 -0
  83. package/ios/Popup/PopupNotify.swift +219 -0
  84. package/ios/Popup/PopupPromotion.swift +74 -0
  85. package/ios/PopupView/FullscreenPopup.swift +251 -0
  86. package/ios/{Popup → PopupView}/Modifiers.swift +6 -20
  87. package/ios/{Popup → PopupView}/PopupView.swift +38 -146
  88. package/ios/PopupView/Utils++.swift +281 -0
  89. package/ios/ProgressInfo/ProgressInfo.swift +297 -0
  90. package/ios/Radio/Radio.swift +69 -0
  91. package/ios/Rating/Rating.swift +83 -0
  92. package/{example/ios/Example/Preview Content/Preview Assets.xcassets/Contents.json → ios/Resources/MoMoUIKitsColors.xcassets/AccentColor.colorset/Contents.json} +5 -0
  93. package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/Text.colorset/Contents.json +3 -3
  94. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/Contents.json +9 -0
  95. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-default.colorset/Contents.json +38 -0
  96. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-disable.colorset/Contents.json +38 -0
  97. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-pressed.colorset/Contents.json +38 -0
  98. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-selected.colorset/Contents.json +38 -0
  99. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-surface.colorset/Contents.json +38 -0
  100. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-tonal.colorset/Contents.json +38 -0
  101. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/border-default.colorset/Contents.json +38 -0
  102. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/border-disable.colorset/Contents.json +38 -0
  103. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/gradient.colorset/Contents.json +38 -0
  104. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/primary.colorset/Contents.json +38 -0
  105. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/secondary.colorset/Contents.json +38 -0
  106. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-container.colorset/Contents.json +38 -0
  107. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-primary.colorset/Contents.json +38 -0
  108. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-secondary.colorset/Contents.json +38 -0
  109. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-default.colorset/Contents.json +38 -0
  110. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-disable.colorset/Contents.json +38 -0
  111. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-hint.colorset/Contents.json +38 -0
  112. package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-secondary.colorset/Contents.json +38 -0
  113. package/ios/ScrollIndicator/ScrollIndicator.swift +110 -0
  114. package/ios/Skeleton/Skeleton.swift +99 -0
  115. package/ios/Slider/Slider.swift +237 -0
  116. package/ios/StatusBarTap/StatusBarTap.h +13 -0
  117. package/ios/StatusBarTap/StatusBarTap.m +75 -0
  118. package/ios/Stepper/Stepper.swift +221 -0
  119. package/ios/Steps/Steps.swift +467 -0
  120. package/ios/SuggestAction/SuggestAction.swift +100 -0
  121. package/ios/Swipeable/SwipeCell.swift +226 -31
  122. package/ios/Swipeable/SwipeCellModel.swift +21 -0
  123. package/ios/Switch/Switch.swift +69 -0
  124. package/ios/TabView/TabView.swift +534 -0
  125. package/ios/Tag/Tag.swift +99 -0
  126. package/ios/Template/Logo/Logo.swift +75 -0
  127. package/ios/Template/TrustBanner/TrustBanner.swift +123 -0
  128. package/ios/Title/Title.swift +270 -0
  129. package/ios/Tooltip/Tooltip.swift +486 -0
  130. package/ios/Typography/FontScale.swift +103 -0
  131. package/ios/Typography/FontScaleStore.swift +58 -0
  132. package/ios/Typography/KitDesignSystem.swift +17 -0
  133. package/ios/Typography/Text.swift +262 -0
  134. package/ios/Typography/Typography.swift +80 -23
  135. package/ios/Uploader/Uploader.swift +174 -0
  136. package/ios/native-kits.podspec +73 -13
  137. package/ios-demo/MoMoUIKitsDemo.podspec +20 -0
  138. package/ios-demo/Resources/dot_loading.json +558 -0
  139. package/ios-demo/Resources/icon.json +4052 -0
  140. package/ios-demo/Resources/lottie_circle_loader.json +1 -0
  141. package/ios-demo/Sources/MoMoUIKitsDemo/DemoScaffold.swift +48 -0
  142. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsBadgeDemoView.swift +25 -0
  143. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsButtonDemoView.swift +26 -0
  144. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsCheckboxDemoView.swift +19 -0
  145. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsChipDemoView.swift +33 -0
  146. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsInputDemoView.swift +48 -0
  147. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsPopupDemoView.swift +21 -0
  148. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsRadioDemoView.swift +17 -0
  149. package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsTypographyDemoView.swift +28 -0
  150. package/ios-demo/Sources/MoMoUIKitsDemo/MoMoUIKitsDemoContext.swift +31 -0
  151. package/ios-demo/Sources/MoMoUIKitsDemo/MoMoUIKitsDemoFactory.swift +24 -0
  152. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/AnimatedHeaderDemo.swift +110 -0
  153. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/AvatarDemo.swift +107 -0
  154. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BadgeDemo.swift +75 -0
  155. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BaselineView.swift +117 -0
  156. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BottomTabDemo.swift +89 -0
  157. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ButtonDemo.swift +108 -0
  158. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CarouselDemo.swift +96 -0
  159. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CheckboxDemo.swift +60 -0
  160. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ChipDemo.swift +76 -0
  161. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CollapseDemo.swift +102 -0
  162. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ContentView.swift +107 -0
  163. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DateTimePickerDemo.swift +100 -0
  164. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DemoScreen.swift +420 -0
  165. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DividerDemo.swift +56 -0
  166. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/HeaderUserDemo.swift +49 -0
  167. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +276 -0
  168. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IconButtonDemo.swift +93 -0
  169. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IconDemo.swift +81 -0
  170. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ImageDemo.swift +65 -0
  171. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InformationDemo.swift +96 -0
  172. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDemo.swift +117 -0
  173. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDropDownDemo.swift +94 -0
  174. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputMoneyDemo.swift +94 -0
  175. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputOTPDemo.swift +88 -0
  176. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputPhoneNumberDemo.swift +120 -0
  177. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputSearchDemo.swift +85 -0
  178. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputTextAreaDemo.swift +87 -0
  179. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/LoaderDemo.swift +73 -0
  180. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/LocalizeDemo.swift +235 -0
  181. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/NavigationDemo.swift +241 -0
  182. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PaginationDemo.swift +68 -0
  183. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PlaygroundData.swift +76 -0
  184. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupDisplayDemo.swift +175 -0
  185. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupNotifyDemo.swift +95 -0
  186. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupPromotionDemo.swift +67 -0
  187. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ProgressInfoDemo.swift +101 -0
  188. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RadioDemo.swift +64 -0
  189. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RatingDemo.swift +68 -0
  190. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SectionDemo.swift +83 -0
  191. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SkeletonDemo.swift +61 -0
  192. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SliderDemo.swift +90 -0
  193. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SnackBarDemo.swift +82 -0
  194. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepperDemo.swift +93 -0
  195. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepsDemo.swift +114 -0
  196. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SuggestActionDemo.swift +90 -0
  197. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwipeDemo.swift +107 -0
  198. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwitchDemo.swift +58 -0
  199. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TabViewDemo.swift +114 -0
  200. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TagDemo.swift +86 -0
  201. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ThemeDemo.swift +181 -0
  202. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TitleDemo.swift +104 -0
  203. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TooltipDemo.swift +118 -0
  204. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TypographyDemo.swift +87 -0
  205. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/UploaderDemo.swift +85 -0
  206. package/ios-demo/Sources/MoMoUIKitsDemo/SwiftUIDemoBrowserView.swift +53 -0
  207. package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoModels.swift +15 -0
  208. package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoRegistry.swift +73 -0
  209. package/package.json +6 -6
  210. package/publish.sh +554 -20
  211. package/scripts/gen-ios-color.mjs +136 -0
  212. package/CODE_OF_CONDUCT.md +0 -133
  213. package/CONTRIBUTING.md +0 -114
  214. package/LICENSE +0 -20
  215. package/android/build.gradle +0 -82
  216. package/android/gradle.properties +0 -5
  217. package/android/src/main/AndroidManifest.xml +0 -4
  218. package/android/src/main/java/com/momoplatform/nativekits/NativeKitsPackage.kt +0 -17
  219. package/android/src/main/java/com/momoplatform/nativekits/NativeKitsViewManager.kt +0 -20
  220. package/example/ios/Example/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -63
  221. package/example/ios/Example/ComponentDetail.swift +0 -35
  222. package/example/ios/Example/ComponentItem.swift +0 -24
  223. package/example/ios/Example/ComponentModel.swift +0 -33
  224. package/example/ios/Example/ContentView.swift +0 -53
  225. package/example/ios/Example/Example.entitlements +0 -10
  226. package/example/ios/Example/Foundation/ButtonDemo.swift +0 -80
  227. package/example/ios/Example/Foundation/Popup/ActionSheets.swift +0 -136
  228. package/example/ios/Example/Foundation/Popup/Floats.swift +0 -127
  229. package/example/ios/Example/Foundation/Popup/Popups.swift +0 -101
  230. package/example/ios/Example/Foundation/PopupDemo.swift +0 -366
  231. package/example/ios/Example/Foundation/TextInputDemo.swift +0 -31
  232. package/example/ios/Example/Foundation/TypographyDemo.swift +0 -53
  233. package/example/ios/Example/Foundation.swift +0 -26
  234. package/example/ios/Example/Info.plist +0 -18
  235. package/example/ios/Example/Library/SwipeableDemo.swift +0 -105
  236. package/example/ios/Example/Library.swift +0 -26
  237. package/example/ios/Example/Main.swift +0 -11
  238. package/example/ios/Example/Overview.swift +0 -20
  239. package/example/ios/Example/Resource/SFProText-Black.ttf +0 -0
  240. package/example/ios/Example/Resource/SFProText-Bold.ttf +0 -0
  241. package/example/ios/Example/Resource/SFProText-Heavy.ttf +0 -0
  242. package/example/ios/Example/Resource/SFProText-Light.ttf +0 -0
  243. package/example/ios/Example/Resource/SFProText-Medium.ttf +0 -0
  244. package/example/ios/Example/Resource/SFProText-Regular.ttf +0 -0
  245. package/example/ios/Example/Resource/SFProText-Semibold.ttf +0 -0
  246. package/example/ios/Example/Resource/SFProText-Thin.ttf +0 -0
  247. package/example/ios/Example/Resource/SFProText-Ultralight.ttf +0 -0
  248. package/example/ios/Example/Resource/foundation.json +0 -33
  249. package/example/ios/Example/Resource/library.json +0 -8
  250. package/example/ios/Example/Utils.swift +0 -30
  251. package/example/ios/Example/ViewModifier/DarkViewModifier.swift +0 -22
  252. package/example/ios/Example.xcodeproj/project.pbxproj +0 -570
  253. package/example/ios/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  254. package/example/ios/Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  255. package/example/ios/Example.xcodeproj/project.xcworkspace/xcuserdata/wem.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  256. package/example/ios/Example.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
  257. package/example/ios/Example.xcworkspace/contents.xcworkspacedata +0 -10
  258. package/example/ios/Example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  259. package/example/ios/Example.xcworkspace/xcuserdata/wem.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  260. package/example/ios/Example.xcworkspace/xcuserdata/wem.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +0 -6
  261. package/example/ios/Podfile +0 -6
  262. package/example/ios/Podfile.lock +0 -16
  263. package/example/ios/Pods/Local Podspecs/MoMoUIKits.podspec.json +0 -29
  264. package/example/ios/Pods/Manifest.lock +0 -16
  265. package/example/ios/Pods/Pods.xcodeproj/project.pbxproj +0 -661
  266. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/MoMoUIKits.xcscheme +0 -58
  267. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/Pods-Example.xcscheme +0 -58
  268. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/xcschememanagement.plist +0 -25
  269. package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits-dummy.m +0 -5
  270. package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits-prefix.pch +0 -12
  271. package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits-umbrella.h +0 -16
  272. package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits.debug.xcconfig +0 -12
  273. package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits.modulemap +0 -6
  274. package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits.release.xcconfig +0 -12
  275. package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-acknowledgements.markdown +0 -3
  276. package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-acknowledgements.plist +0 -29
  277. package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-dummy.m +0 -5
  278. package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-umbrella.h +0 -16
  279. package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example.debug.xcconfig +0 -14
  280. package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example.modulemap +0 -6
  281. package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example.release.xcconfig +0 -14
  282. package/ios/Colors+Spacing/Radius.swift +0 -11
  283. package/ios/Popup/Utils++.swift +0 -163
  284. package/ios/Theme.md +0 -18
  285. /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/Background.colorset/Contents.json +0 -0
  286. /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/Border.colorset/Contents.json +0 -0
  287. /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/Card.colorset/Contents.json +0 -0
  288. /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/Contents.json +0 -0
  289. /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/Error.colorset/Contents.json +0 -0
  290. /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/Primary.colorset/Contents.json +0 -0
  291. /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/PrimaryDark.colorset/Contents.json +0 -0
  292. /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/PrimaryLight.colorset/Contents.json +0 -0
  293. /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/Secondary.colorset/Contents.json +0 -0
  294. /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/Success.colorset/Contents.json +0 -0
  295. /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/TextSecondary.colorset/Contents.json +0 -0
  296. /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/Warning.colorset/Contents.json +0 -0
@@ -0,0 +1,38 @@
1
+ {
2
+ "colors": [
3
+ {
4
+ "color": {
5
+ "color-space": "srgb",
6
+ "components": {
7
+ "red": "0x30",
8
+ "green": "0x32",
9
+ "blue": "0x33",
10
+ "alpha": "1.000"
11
+ }
12
+ },
13
+ "idiom": "universal"
14
+ },
15
+ {
16
+ "color": {
17
+ "color-space": "srgb",
18
+ "components": {
19
+ "red": "0xFF",
20
+ "green": "0xFF",
21
+ "blue": "0xFF",
22
+ "alpha": "1.000"
23
+ }
24
+ },
25
+ "idiom": "universal",
26
+ "appearances": [
27
+ {
28
+ "appearance": "luminosity",
29
+ "value": "dark"
30
+ }
31
+ ]
32
+ }
33
+ ],
34
+ "info": {
35
+ "author": "xcode",
36
+ "version": 1
37
+ }
38
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "colors": [
3
+ {
4
+ "color": {
5
+ "color-space": "srgb",
6
+ "components": {
7
+ "red": "0xC6",
8
+ "green": "0xC6",
9
+ "blue": "0xC6",
10
+ "alpha": "1.000"
11
+ }
12
+ },
13
+ "idiom": "universal"
14
+ },
15
+ {
16
+ "color": {
17
+ "color-space": "srgb",
18
+ "components": {
19
+ "red": "0x50",
20
+ "green": "0x50",
21
+ "blue": "0x50",
22
+ "alpha": "1.000"
23
+ }
24
+ },
25
+ "idiom": "universal",
26
+ "appearances": [
27
+ {
28
+ "appearance": "luminosity",
29
+ "value": "dark"
30
+ }
31
+ ]
32
+ }
33
+ ],
34
+ "info": {
35
+ "author": "xcode",
36
+ "version": 1
37
+ }
38
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "colors": [
3
+ {
4
+ "color": {
5
+ "color-space": "srgb",
6
+ "components": {
7
+ "red": "0x72",
8
+ "green": "0x72",
9
+ "blue": "0x72",
10
+ "alpha": "1.000"
11
+ }
12
+ },
13
+ "idiom": "universal"
14
+ },
15
+ {
16
+ "color": {
17
+ "color-space": "srgb",
18
+ "components": {
19
+ "red": "0x72",
20
+ "green": "0x72",
21
+ "blue": "0x72",
22
+ "alpha": "1.000"
23
+ }
24
+ },
25
+ "idiom": "universal",
26
+ "appearances": [
27
+ {
28
+ "appearance": "luminosity",
29
+ "value": "dark"
30
+ }
31
+ ]
32
+ }
33
+ ],
34
+ "info": {
35
+ "author": "xcode",
36
+ "version": 1
37
+ }
38
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "colors": [
3
+ {
4
+ "color": {
5
+ "color-space": "srgb",
6
+ "components": {
7
+ "red": "0x48",
8
+ "green": "0x48",
9
+ "blue": "0x48",
10
+ "alpha": "1.000"
11
+ }
12
+ },
13
+ "idiom": "universal"
14
+ },
15
+ {
16
+ "color": {
17
+ "color-space": "srgb",
18
+ "components": {
19
+ "red": "0xB0",
20
+ "green": "0xB0",
21
+ "blue": "0xB0",
22
+ "alpha": "1.000"
23
+ }
24
+ },
25
+ "idiom": "universal",
26
+ "appearances": [
27
+ {
28
+ "appearance": "luminosity",
29
+ "value": "dark"
30
+ }
31
+ ]
32
+ }
33
+ ],
34
+ "info": {
35
+ "author": "xcode",
36
+ "version": 1
37
+ }
38
+ }
@@ -0,0 +1,110 @@
1
+ import Foundation
2
+ import SwiftUI
3
+
4
+ public struct ScrollViewWithScrollBar<Content: View>: View {
5
+ let INDICATOR_HEIGHT: CGFloat = 4
6
+ @State var position = CGPoint(x: 0, y: 2) //2 is INDICATOR_HEIGHT/2
7
+ @State var contentSize: CGFloat = 0
8
+ @State var scrollViewWidth: CGFloat = 0
9
+ var indicatorWidth: CGFloat
10
+ var indicatorContainerWidth: CGFloat
11
+ var indicatorColor: Color
12
+ var indicatorContainerColor: Color
13
+ var spacing: CGFloat = 4
14
+ @ViewBuilder var content: () -> Content
15
+
16
+ public init(
17
+ indicatorWidth: CGFloat = 12, indicatorContainerWidth: CGFloat = 36,
18
+ indicatorColor: Color = Colors.primary, indicatorContainerColor: Color = Colors.black06,
19
+ spacing: CGFloat = 4,
20
+ @ViewBuilder content: @escaping () -> Content
21
+ ) {
22
+ self.indicatorWidth = indicatorWidth
23
+ self.indicatorContainerWidth = indicatorContainerWidth
24
+ self.indicatorColor = indicatorColor
25
+ self.indicatorContainerColor = indicatorContainerColor
26
+ self.content = content
27
+ self.spacing = spacing
28
+ }
29
+
30
+ // MARK: Public
31
+
32
+ public var body: some View {
33
+ return VStack(spacing: spacing) {
34
+ ScrollView(.horizontal, showsIndicators: false) {
35
+ HStack {
36
+ content()
37
+ }
38
+ .fixedSize(horizontal: true, vertical: false)
39
+ .overlay(
40
+ GeometryReader { proxy in
41
+ Color.clear
42
+ .preference(
43
+ key: ViewOffsetKey.self,
44
+ value: -proxy.frame(in: .named("scroll")).origin.x
45
+ )
46
+ .preference(
47
+ key: ContentSizeKey.self,
48
+ value: proxy.size.width)
49
+ },
50
+ alignment: .topLeading
51
+ )
52
+ .onPreferenceChange(ContentSizeKey.self) { newContentSize in
53
+ if newContentSize > 0 {
54
+ self.contentSize = newContentSize
55
+ if self.position == CGPoint(x: 0, y: 2) {
56
+ self.position = CGPoint(x: indicatorWidth / 2, y: INDICATOR_HEIGHT / 2)
57
+ }
58
+ }
59
+ }
60
+ .onPreferenceChange(ViewOffsetKey.self) { offset in
61
+ let newPosition =
62
+ (offset * ((indicatorContainerWidth - indicatorWidth) / (contentSize - scrollViewWidth)))
63
+ + indicatorWidth / 2
64
+
65
+ if !newPosition.isNaN {
66
+ self.position = CGPoint(x: newPosition, y: INDICATOR_HEIGHT / 2)
67
+ }
68
+ }
69
+ }.background(
70
+ GeometryReader { proxy in
71
+ Color.clear.onAppear {
72
+ self.scrollViewWidth = proxy.size.width
73
+ }
74
+ }
75
+ ).coordinateSpace(name: "scroll")
76
+
77
+ HStack(spacing: 0) {
78
+ HStack(spacing: 0) {}.frame(width: indicatorWidth, height: INDICATOR_HEIGHT)
79
+ .background(indicatorColor)
80
+ .cornerRadius(8)
81
+ .position(self.position)
82
+ }.frame(width: indicatorContainerWidth, height: INDICATOR_HEIGHT, alignment: .leading)
83
+ .background(indicatorContainerColor).cornerRadius(8)
84
+ }
85
+ }
86
+ }
87
+
88
+ // MARK: - ViewOffsetKey
89
+
90
+ struct ViewOffsetKey: PreferenceKey {
91
+ typealias Value = CGFloat
92
+
93
+ static var defaultValue = CGFloat.zero
94
+
95
+ static func reduce(value: inout Value, nextValue: () -> Value) {
96
+ value += nextValue()
97
+ }
98
+ }
99
+
100
+ // MARK: - ContentSizeKey
101
+
102
+ struct ContentSizeKey: PreferenceKey {
103
+ typealias Value = CGFloat
104
+
105
+ static var defaultValue = CGFloat.zero
106
+
107
+ static func reduce(value: inout Value, nextValue: () -> Value) {
108
+ value = nextValue()
109
+ }
110
+ }
@@ -0,0 +1,99 @@
1
+ import Foundation
2
+ import SwiftUI
3
+
4
+ /// Native SwiftUI port of the Compose `Skeleton` component.
5
+ ///
6
+ /// Fills the available space with a base placeholder color and overlays a
7
+ /// horizontal shimmer gradient that animates left-to-right on an infinite loop.
8
+ ///
9
+ /// Mirrors the Compose surface: `Skeleton()` takes no required arguments and
10
+ /// fills its container. The shimmer animation parameters match the Compose
11
+ /// defaults (`durationMillis = 1000`, shimmer band = 60% of container width).
12
+ public struct Skeleton: View {
13
+ // Matches Compose `DEFAULT_DURATION_MILLIS = 1000`.
14
+ private let durationMillis: Int
15
+ // Matches Compose `angleOfAxisY = 0f` (horizontal gradient).
16
+ private let angleOfAxisY: CGFloat
17
+
18
+ public init(
19
+ durationMillis: Int = 1000,
20
+ angleOfAxisY: CGFloat = 0
21
+ ) {
22
+ self.durationMillis = durationMillis
23
+ self.angleOfAxisY = angleOfAxisY
24
+ }
25
+
26
+ public var body: some View {
27
+ GeometryReader { proxy in
28
+ ShimmerLoading(
29
+ size: proxy.size,
30
+ durationMillis: durationMillis,
31
+ angleOfAxisY: angleOfAxisY
32
+ )
33
+ }
34
+ // Compose base background (`Colors.black_05`).
35
+ .background(Colors.black05)
36
+ }
37
+ }
38
+
39
+ /// Internal shimmer overlay. Reproduces Compose's `Modifier.shimmerLoadingAnimation`:
40
+ /// a linear gradient band (60% of the container width) translated across the
41
+ /// surface on an infinite, restarting, linearly-eased loop.
42
+ private struct ShimmerLoading: View {
43
+ let size: CGSize
44
+ let durationMillis: Int
45
+ let angleOfAxisY: CGFloat
46
+
47
+ @State private var phase: CGFloat = 0
48
+
49
+ // Matches Compose `SHADOW_BRUSH_PERCENTAGE = 0.6f`.
50
+ private static let shadowBrushPercentage: CGFloat = 0.6
51
+
52
+ // Pre-computed shimmer colors (Colors.black_05, black_03, black_05).
53
+ private static let shimmerColors: [Color] = [
54
+ Colors.black05,
55
+ Colors.black03,
56
+ Colors.black05,
57
+ ]
58
+
59
+ private var widthOfShadowBrush: CGFloat {
60
+ (size.width * Self.shadowBrushPercentage).rounded(.towardZero)
61
+ }
62
+
63
+ // Compose animates from 0 to (durationMillis + widthOfShadowBrush). Since the
64
+ // band is anchored at the animated value, the meaningful travel range spans
65
+ // from off-screen-left to off-screen-right: -widthOfShadowBrush ... maxWidth.
66
+ private var animationTarget: CGFloat {
67
+ size.width + widthOfShadowBrush
68
+ }
69
+
70
+ var body: some View {
71
+ let startX = phase - widthOfShadowBrush
72
+ let endX = phase
73
+
74
+ Rectangle()
75
+ .fill(
76
+ LinearGradient(
77
+ gradient: Gradient(colors: Self.shimmerColors),
78
+ startPoint: .init(
79
+ x: size.width > 0 ? startX / size.width : 0,
80
+ y: 0
81
+ ),
82
+ endPoint: .init(
83
+ x: size.width > 0 ? endX / size.width : 0,
84
+ y: size.height > 0 ? angleOfAxisY / size.height : 0
85
+ )
86
+ )
87
+ )
88
+ .onAppear {
89
+ guard size.width > 0 else { return }
90
+ phase = 0
91
+ withAnimation(
92
+ .linear(duration: Double(durationMillis) / 1000.0)
93
+ .repeatForever(autoreverses: false)
94
+ ) {
95
+ phase = animationTarget
96
+ }
97
+ }
98
+ }
99
+ }
@@ -0,0 +1,237 @@
1
+ import SwiftUI
2
+
3
+ // ── Design constants ─────────────────────────────────────────────────────────
4
+
5
+ private let THUMB_SIZE: CGFloat = 20
6
+ private let THUMB_BORDER: CGFloat = 3
7
+ private let TRACK_HEIGHT: CGFloat = 4
8
+ private let LABEL_GAP: CGFloat = 4 // space between label and thumb top (Spacing.XS)
9
+
10
+ // ── Pure helpers (mirrors Compose / RN helpers) ──────────────────────────────
11
+
12
+ private func clampF(_ value: CGFloat, _ minV: CGFloat, _ maxV: CGFloat) -> CGFloat {
13
+ Swift.min(Swift.max(value, minV), maxV)
14
+ }
15
+
16
+ /// Converts a raw touch position into a snapped slider value.
17
+ /// Direct port of Compose getValueForPosition().
18
+ private func getValueForPosition(
19
+ positionInView: CGFloat,
20
+ containerWidth: CGFloat,
21
+ thumbWidth: CGFloat,
22
+ minV: CGFloat,
23
+ maxV: CGFloat,
24
+ step: CGFloat
25
+ ) -> CGFloat {
26
+ let availableSpace = containerWidth - thumbWidth
27
+ if availableSpace <= 0 { return minV }
28
+ let relStepUnit = step / (maxV - minV)
29
+ var relPosition = (positionInView - thumbWidth / 2) / availableSpace
30
+ let relOffset = relPosition.truncatingRemainder(dividingBy: relStepUnit)
31
+ relPosition -= relOffset
32
+ if relStepUnit != 0, relOffset / relStepUnit >= 0.5 { relPosition += relStepUnit }
33
+ let steps = (relPosition / relStepUnit).rounded()
34
+ return clampF(minV + steps * step, minV, maxV)
35
+ }
36
+
37
+ /// Direct port of Compose isLowCloser().
38
+ private func isLowCloser(_ downX: CGFloat, _ lowPosition: CGFloat, _ highPosition: CGFloat) -> Bool {
39
+ if lowPosition == highPosition { return downX < lowPosition }
40
+ return abs(downX - lowPosition) < abs(downX - highPosition)
41
+ }
42
+
43
+ private func valueToFraction(_ value: CGFloat, _ minV: CGFloat, _ maxV: CGFloat) -> CGFloat {
44
+ if maxV == minV { return 0 }
45
+ return clampF((value - minV) / (maxV - minV), 0, 1)
46
+ }
47
+
48
+ private func formatLabel(_ value: CGFloat) -> String {
49
+ if value == value.rounded() {
50
+ return String(Int(value))
51
+ }
52
+ return String(format: "%.1f", value)
53
+ }
54
+
55
+ // ── Component ─────────────────────────────────────────────────────────────────
56
+
57
+ /// Range slider (or single-thumb when `disableRange` = true), ported from Compose.
58
+ ///
59
+ /// SwiftUI ships a built-in `Slider`; this custom type is named `MomoSlider`
60
+ /// (convention, like `MomoText`) to avoid module-wide shadowing.
61
+ public struct MomoSlider: View {
62
+ @Environment(\.appTheme) private var theme
63
+
64
+ private let minV: CGFloat
65
+ private let maxV: CGFloat
66
+ private let step: CGFloat
67
+ private let initLow: CGFloat
68
+ private let initHigh: CGFloat
69
+ private let minRange: CGFloat
70
+ private let disableRange: Bool
71
+ private let floatingLabel: Bool
72
+ private let disabled: Bool
73
+ private let onValueChanged: (CGFloat, CGFloat, Bool) -> Void
74
+ private let onSliderTouchStart: (CGFloat, CGFloat) -> Void
75
+ private let onSliderTouchEnd: (CGFloat, CGFloat) -> Void
76
+
77
+ @State private var lowValue: CGFloat = 0
78
+ @State private var highValue: CGFloat = 0
79
+ @State private var draggingLow: Bool = true
80
+ @State private var isDragging: Bool = false
81
+ @State private var didInit: Bool = false
82
+
83
+ public init(
84
+ min: CGFloat,
85
+ max: CGFloat,
86
+ step: CGFloat,
87
+ low: CGFloat? = nil,
88
+ high: CGFloat? = nil,
89
+ minRange: CGFloat = 0,
90
+ disableRange: Bool = false,
91
+ floatingLabel: Bool = false,
92
+ disabled: Bool = false,
93
+ onValueChanged: @escaping (CGFloat, CGFloat, Bool) -> Void = { _, _, _ in },
94
+ onSliderTouchStart: @escaping (CGFloat, CGFloat) -> Void = { _, _ in },
95
+ onSliderTouchEnd: @escaping (CGFloat, CGFloat) -> Void = { _, _ in }
96
+ ) {
97
+ self.minV = min
98
+ self.maxV = max
99
+ self.step = step
100
+ self.minRange = minRange
101
+ self.disableRange = disableRange
102
+ self.floatingLabel = floatingLabel
103
+ self.disabled = disabled
104
+ self.onValueChanged = onValueChanged
105
+ self.onSliderTouchStart = onSliderTouchStart
106
+ self.onSliderTouchEnd = onSliderTouchEnd
107
+
108
+ self.initLow = clampF(low ?? min, min, max)
109
+ self.initHigh = disableRange ? max : clampF(high ?? max, min, max)
110
+ }
111
+
112
+ private var thumbColor: Color { disabled ? theme.colors.text.disable : theme.colors.primary }
113
+ private var trackActiveColor: Color { disabled ? theme.colors.text.disable : theme.colors.primary }
114
+ private var trackInactiveColor: Color { theme.colors.background.default }
115
+
116
+ public var body: some View {
117
+ GeometryReader { geo in
118
+ let trackWidth = geo.size.width
119
+ let availableWidth = max(trackWidth - THUMB_SIZE, 0)
120
+ let topPad: CGFloat = floatingLabel ? (THUMB_SIZE + LABEL_GAP) : 0
121
+
122
+ let lowFraction = valueToFraction(lowValue, minV, maxV)
123
+ let highFraction = valueToFraction(highValue, minV, maxV)
124
+
125
+ let activeStartFraction = disableRange ? 0 : lowFraction
126
+ let activeEndFraction = disableRange ? lowFraction : highFraction
127
+ let activeStartX = THUMB_SIZE / 2 + availableWidth * activeStartFraction
128
+ let activeWidth = availableWidth * (activeEndFraction - activeStartFraction)
129
+
130
+ ZStack(alignment: .topLeading) {
131
+ // ── Floating label ────────────────────────────────────────────
132
+ if floatingLabel && isDragging {
133
+ let activeFraction = draggingLow ? lowFraction : highFraction
134
+ let activeValue = draggingLow ? lowValue : highValue
135
+ MomoText(formatLabel(activeValue), typography: .descriptionXsRegular, color: theme.colors.text.default)
136
+ .padding(.horizontal, Spacing.XS)
137
+ .padding(.vertical, Spacing.XXS)
138
+ .background(Colors.black01)
139
+ .clipShape(RoundedRectangle(cornerRadius: Radius.XS))
140
+ .offset(x: availableWidth * activeFraction, y: 0)
141
+ }
142
+
143
+ // ── Inactive track (full width) ───────────────────────────────
144
+ Capsule()
145
+ .fill(trackInactiveColor)
146
+ .frame(width: max(trackWidth - THUMB_SIZE, 0), height: TRACK_HEIGHT)
147
+ .offset(x: THUMB_SIZE / 2, y: topPad + (THUMB_SIZE - TRACK_HEIGHT) / 2)
148
+
149
+ // ── Active track (selected range / single value) ──────────────
150
+ if activeWidth > 0 {
151
+ Capsule()
152
+ .fill(trackActiveColor)
153
+ .frame(width: activeWidth, height: TRACK_HEIGHT)
154
+ .offset(x: activeStartX, y: topPad + (THUMB_SIZE - TRACK_HEIGHT) / 2)
155
+ }
156
+
157
+ // ── Low thumb ─────────────────────────────────────────────────
158
+ thumb
159
+ .offset(x: availableWidth * lowFraction, y: topPad)
160
+
161
+ // ── High thumb (range mode only) ──────────────────────────────
162
+ if !disableRange {
163
+ thumb
164
+ .offset(x: availableWidth * highFraction, y: topPad)
165
+ }
166
+ }
167
+ .frame(width: trackWidth, height: topPad + THUMB_SIZE, alignment: .topLeading)
168
+ .contentShape(Rectangle())
169
+ .gesture(dragGesture(trackWidth: trackWidth))
170
+ }
171
+ .frame(height: (floatingLabel ? (THUMB_SIZE + LABEL_GAP) : 0) + THUMB_SIZE)
172
+ .onAppear {
173
+ if !didInit {
174
+ lowValue = initLow
175
+ highValue = initHigh
176
+ didInit = true
177
+ }
178
+ }
179
+ }
180
+
181
+ private var thumb: some View {
182
+ Circle()
183
+ .fill(thumbColor)
184
+ .frame(width: THUMB_SIZE, height: THUMB_SIZE)
185
+ .overlay(
186
+ Circle().strokeBorder(theme.colors.background.surface, lineWidth: THUMB_BORDER)
187
+ )
188
+ }
189
+
190
+ private func dragGesture(trackWidth: CGFloat) -> some Gesture {
191
+ DragGesture(minimumDistance: 0)
192
+ .onChanged { gesture in
193
+ if disabled { return }
194
+ let touchX = gesture.location.x
195
+
196
+ if !isDragging {
197
+ // Finger down: pick the closer thumb
198
+ let lowCenterX = THUMB_SIZE / 2 +
199
+ valueToFraction(lowValue, minV, maxV) * (trackWidth - THUMB_SIZE)
200
+ let highCenterX = THUMB_SIZE / 2 +
201
+ valueToFraction(highValue, minV, maxV) * (trackWidth - THUMB_SIZE)
202
+ draggingLow = disableRange || isLowCloser(touchX, lowCenterX, highCenterX)
203
+ isDragging = true
204
+ onSliderTouchStart(lowValue, highValue)
205
+ }
206
+
207
+ applyDrag(positionX: touchX, trackWidthPx: trackWidth)
208
+ }
209
+ .onEnded { _ in
210
+ if disabled { return }
211
+ isDragging = false
212
+ onSliderTouchEnd(lowValue, highValue)
213
+ }
214
+ }
215
+
216
+ private func applyDrag(positionX: CGFloat, trackWidthPx: CGFloat) {
217
+ let snapped = getValueForPosition(
218
+ positionInView: positionX,
219
+ containerWidth: trackWidthPx,
220
+ thumbWidth: THUMB_SIZE,
221
+ minV: minV, maxV: maxV, step: step
222
+ )
223
+ if draggingLow {
224
+ let newLow = clampF(snapped, minV, highValue - minRange)
225
+ if newLow != lowValue {
226
+ lowValue = newLow
227
+ onValueChanged(newLow, highValue, true)
228
+ }
229
+ } else {
230
+ let newHigh = clampF(snapped, lowValue + minRange, maxV)
231
+ if newHigh != highValue {
232
+ highValue = newHigh
233
+ onValueChanged(lowValue, newHigh, true)
234
+ }
235
+ }
236
+ }
237
+ }
@@ -0,0 +1,13 @@
1
+ #import <Foundation/Foundation.h>
2
+
3
+ NS_ASSUME_NONNULL_BEGIN
4
+
5
+ /// Posts `MoMoStatusBarTap.notificationName` on every status-bar tap.
6
+ /// The swizzle installs automatically at framework load (`+load`) — calling
7
+ /// `install` is a no-op kept for explicit/manual triggering.
8
+ @interface MoMoStatusBarTap : NSObject
9
+ @property (class, nonatomic, readonly) NSNotificationName notificationName;
10
+ + (void)install;
11
+ @end
12
+
13
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,75 @@
1
+ #import <UIKit/UIKit.h>
2
+ #import <objc/message.h>
3
+ #import <objc/runtime.h>
4
+ #import "StatusBarTap.h"
5
+
6
+ // Performs the actual swizzle once per process. Safe to call multiple times.
7
+ static void mm_installStatusBarTapSwizzleOnce(void) {
8
+ static dispatch_once_t onceToken;
9
+ dispatch_once(&onceToken, ^{
10
+ Class cls = [UIStatusBarManager class];
11
+ SEL originalSelector = NSSelectorFromString(@"handleTapAction:");
12
+ SEL swizzledSelector = NSSelectorFromString(@"mm_handleTapAction:");
13
+
14
+ Method originalMethod = class_getInstanceMethod(cls, originalSelector);
15
+ Method swizzledMethod = class_getInstanceMethod(cls, swizzledSelector);
16
+ if (!originalMethod || !swizzledMethod) return;
17
+
18
+ // Verify the original method matches the (id) -> void shape we expect.
19
+ // Encoding may include byte offsets (e.g. "v32@0:8@16") so we filter
20
+ // digits out before comparing.
21
+ const char *encPtr = method_getTypeEncoding(originalMethod);
22
+ if (encPtr) {
23
+ NSMutableString *enc = [NSMutableString string];
24
+ for (const char *p = encPtr; *p; p++) {
25
+ if (!(*p >= '0' && *p <= '9')) [enc appendFormat:@"%c", *p];
26
+ }
27
+ if (![enc isEqualToString:@"v@:@"]) return;
28
+ }
29
+
30
+ BOOL didAdd = class_addMethod(cls,
31
+ originalSelector,
32
+ method_getImplementation(swizzledMethod),
33
+ method_getTypeEncoding(swizzledMethod));
34
+ if (didAdd) {
35
+ class_replaceMethod(cls,
36
+ swizzledSelector,
37
+ method_getImplementation(originalMethod),
38
+ method_getTypeEncoding(originalMethod));
39
+ } else {
40
+ method_exchangeImplementations(originalMethod, swizzledMethod);
41
+ }
42
+ });
43
+ }
44
+
45
+ @implementation MoMoStatusBarTap
46
+ + (NSNotificationName)notificationName { return @"statusBarSelected"; }
47
+ + (void)install { mm_installStatusBarTapSwizzleOnce(); }
48
+ @end
49
+
50
+ // MARK: - Swizzle target on UIStatusBarManager
51
+ // `mm_handleTapAction:` is the replacement IMP. After the add/exchange,
52
+ // this selector points at the original UIKit IMP — calling it inside
53
+ // the body invokes UIKit's real handler so UIScrollView.scrollsToTop
54
+ // and any other side effects continue to work.
55
+
56
+ @interface UIStatusBarManager (MoMoStatusBarTap)
57
+ @end
58
+
59
+ @implementation UIStatusBarManager (MoMoStatusBarTap)
60
+
61
+ // Auto-install at framework load. Commented out so the swizzle stays
62
+ // opt-in via `[MoMoStatusBarTap install]`. Uncomment to revert to
63
+ // auto-installation before main().
64
+ //
65
+ // + (void)load {
66
+ // mm_installStatusBarTapSwizzleOnce();
67
+ // }
68
+
69
+ - (void)mm_handleTapAction:(id)action {
70
+ [self mm_handleTapAction:action];
71
+ [[NSNotificationCenter defaultCenter] postNotificationName:MoMoStatusBarTap.notificationName
72
+ object:nil];
73
+ }
74
+
75
+ @end