@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.
- package/CLAUDE.md +99 -0
- package/PUBLISH_GUIDE.md +675 -0
- package/README.md +184 -5
- package/ios/Application/ApplicationEnvironment.swift +71 -0
- package/ios/Application/Components.swift +270 -0
- package/ios/Application/ComposeApi.swift +22 -0
- package/ios/Application/FloatingButton.swift +174 -0
- package/ios/Application/HeaderRight.swift +306 -0
- package/ios/Application/LanguageSource.swift +93 -0
- package/ios/Application/Localize.swift +378 -0
- package/ios/Application/LocalizeModifier.swift +30 -0
- package/ios/Application/MaxApi.swift +18 -0
- package/ios/Application/Navigation/BottomTab/BottomTab.swift +104 -0
- package/ios/Application/Navigation/BottomTab/BottomTabBar.swift +215 -0
- package/ios/Application/Navigation/BottomTab/CurvedContainer.swift +65 -0
- package/ios/Application/Navigation/HeaderBackProps.swift +66 -0
- package/ios/Application/Navigation/HeaderTitle.swift +57 -0
- package/ios/Application/Navigation/HeaderUser.swift +209 -0
- package/ios/Application/Navigation/NavigationContainer.swift +213 -0
- package/ios/Application/Navigation/NavigationOptions.swift +109 -0
- package/ios/Application/Navigation/Navigator.swift +453 -0
- package/ios/Application/Navigation/NavigatorManager.swift +22 -0
- package/ios/Application/Navigation/Overplay/BottomSheet.swift +256 -0
- package/ios/Application/Navigation/Overplay/ModalScreen.swift +74 -0
- package/ios/Application/Navigation/Overplay/SnackBar.swift +144 -0
- package/ios/Application/Navigation/Tracking/ScreenTracker.swift +117 -0
- package/ios/Application/Navigation/component/Header.swift +178 -0
- package/ios/Application/Navigation/component/HeaderBackground.swift +83 -0
- package/ios/Application/Navigation/component/HeaderColor.swift +65 -0
- package/ios/Application/Navigation/component/HeaderRightWidthKey.swift +11 -0
- package/ios/Application/Navigation/component/NavigationFooter.swift +90 -0
- package/ios/Application/Navigation/component/NavigationHeaderRight.swift +196 -0
- package/ios/Application/Screen.swift +250 -0
- package/ios/Application/StackScreen.swift +492 -0
- package/ios/Avatar/Avatar.swift +193 -0
- package/ios/Badge/Badge.swift +84 -0
- package/ios/Badge/BadgeDot.swift +31 -0
- package/ios/Badge/BadgeRibbon.swift +319 -0
- package/ios/BaselineView/BaselineView.swift +163 -0
- package/ios/Button/Button.swift +232 -84
- package/ios/CalculatorKeyboard/CalculatorKeyboard.swift +126 -0
- package/ios/Carousel/Carousel.swift +196 -0
- package/ios/Checkbox/Checkbox.swift +77 -0
- package/ios/Chip/Chip.swift +120 -0
- package/ios/Collapse/Collapse.swift +192 -0
- package/ios/{Colors+Spacing → Colors+Radius+Spacing}/Colors.swift +42 -37
- package/ios/Colors+Radius+Spacing/Radius.swift +22 -0
- package/ios/{Colors+Spacing → Colors+Radius+Spacing}/Spacing.swift +3 -1
- package/ios/Colors+Radius+Spacing/Theme.swift +295 -0
- package/ios/DateTimePicker/DateTimePicker.swift +212 -0
- package/ios/DateTimePicker/DateTimePickerTypes.swift +55 -0
- package/ios/DateTimePicker/DateTimePickerUtils.swift +167 -0
- package/ios/DateTimePicker/WheelPicker.swift +165 -0
- package/ios/Divider/Divider.swift +16 -0
- package/ios/Extensions/ActiveOpacityButtonStyle.swift +14 -0
- package/ios/Extensions/Color++.swift +32 -0
- package/ios/Icon/Icon.swift +69 -0
- package/ios/IconButton/IconButton.swift +140 -0
- package/ios/Image/Image.swift +87 -0
- package/ios/Information/Information.swift +156 -0
- package/ios/Input/ErrorView.swift +58 -0
- package/ios/Input/Input.swift +461 -77
- package/ios/Input/InputPhoneNumber.swift +192 -0
- package/ios/Input/InputSearch.swift +301 -0
- package/ios/Input/InputTextArea.swift +318 -0
- package/ios/InputDropDown/InputDropDown.swift +201 -0
- package/ios/InputMoney/InputMoney.swift +405 -0
- package/ios/InputOTP/InputOTP.swift +211 -0
- package/ios/Layout/GridContext.swift +30 -0
- package/ios/Layout/Item.swift +42 -0
- package/ios/Layout/Section.swift +134 -0
- package/ios/Loader/Loader.swift +113 -0
- package/ios/Lottie/LottieView.swift +86 -0
- package/ios/MoMoUIKits.podspec +5 -0
- package/ios/OTPKeyboard/KeyboardButton.swift +13 -5
- package/ios/OTPKeyboard/OTPKeyboard.swift +1 -1
- package/ios/Pagination/PaginationDot.swift +61 -0
- package/ios/Pagination/PaginationNumber.swift +35 -0
- package/ios/Pagination/PaginationScroll.swift +101 -0
- package/ios/Pagination/PaginationWhiteDot.swift +37 -0
- package/ios/Popup/PopupDisplay.swift +279 -0
- package/ios/Popup/PopupInput.swift +92 -0
- package/ios/Popup/PopupNotify.swift +219 -0
- package/ios/Popup/PopupPromotion.swift +74 -0
- package/ios/PopupView/FullscreenPopup.swift +251 -0
- package/ios/{Popup → PopupView}/Modifiers.swift +6 -20
- package/ios/{Popup → PopupView}/PopupView.swift +38 -146
- package/ios/PopupView/Utils++.swift +281 -0
- package/ios/ProgressInfo/ProgressInfo.swift +297 -0
- package/ios/Radio/Radio.swift +69 -0
- package/ios/Rating/Rating.swift +83 -0
- package/{example/ios/Example/Preview Content/Preview Assets.xcassets/Contents.json → ios/Resources/MoMoUIKitsColors.xcassets/AccentColor.colorset/Contents.json} +5 -0
- package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/Text.colorset/Contents.json +3 -3
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/Contents.json +9 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-default.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-disable.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-pressed.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-selected.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-surface.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-tonal.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/border-default.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/border-disable.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/gradient.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/primary.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/secondary.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-container.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-primary.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-secondary.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-default.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-disable.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-hint.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-secondary.colorset/Contents.json +38 -0
- package/ios/ScrollIndicator/ScrollIndicator.swift +110 -0
- package/ios/Skeleton/Skeleton.swift +99 -0
- package/ios/Slider/Slider.swift +237 -0
- package/ios/StatusBarTap/StatusBarTap.h +13 -0
- package/ios/StatusBarTap/StatusBarTap.m +75 -0
- package/ios/Stepper/Stepper.swift +221 -0
- package/ios/Steps/Steps.swift +467 -0
- package/ios/SuggestAction/SuggestAction.swift +100 -0
- package/ios/Swipeable/SwipeCell.swift +226 -31
- package/ios/Swipeable/SwipeCellModel.swift +21 -0
- package/ios/Switch/Switch.swift +69 -0
- package/ios/TabView/TabView.swift +534 -0
- package/ios/Tag/Tag.swift +99 -0
- package/ios/Template/Logo/Logo.swift +75 -0
- package/ios/Template/TrustBanner/TrustBanner.swift +123 -0
- package/ios/Title/Title.swift +270 -0
- package/ios/Tooltip/Tooltip.swift +486 -0
- package/ios/Typography/FontScale.swift +103 -0
- package/ios/Typography/FontScaleStore.swift +58 -0
- package/ios/Typography/KitDesignSystem.swift +17 -0
- package/ios/Typography/Text.swift +262 -0
- package/ios/Typography/Typography.swift +80 -23
- package/ios/Uploader/Uploader.swift +174 -0
- package/ios/native-kits.podspec +73 -13
- package/ios-demo/MoMoUIKitsDemo.podspec +20 -0
- package/ios-demo/Resources/dot_loading.json +558 -0
- package/ios-demo/Resources/icon.json +4052 -0
- package/ios-demo/Resources/lottie_circle_loader.json +1 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/DemoScaffold.swift +48 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsBadgeDemoView.swift +25 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsButtonDemoView.swift +26 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsCheckboxDemoView.swift +19 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsChipDemoView.swift +33 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsInputDemoView.swift +48 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsPopupDemoView.swift +21 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsRadioDemoView.swift +17 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/Demos/UIKitsTypographyDemoView.swift +28 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/MoMoUIKitsDemoContext.swift +31 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/MoMoUIKitsDemoFactory.swift +24 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/AnimatedHeaderDemo.swift +110 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/AvatarDemo.swift +107 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BadgeDemo.swift +75 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BaselineView.swift +117 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BottomTabDemo.swift +89 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ButtonDemo.swift +108 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CarouselDemo.swift +96 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CheckboxDemo.swift +60 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ChipDemo.swift +76 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CollapseDemo.swift +102 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ContentView.swift +107 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DateTimePickerDemo.swift +100 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DemoScreen.swift +420 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DividerDemo.swift +56 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/HeaderUserDemo.swift +49 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +276 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IconButtonDemo.swift +93 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IconDemo.swift +81 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ImageDemo.swift +65 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InformationDemo.swift +96 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDemo.swift +117 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDropDownDemo.swift +94 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputMoneyDemo.swift +94 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputOTPDemo.swift +88 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputPhoneNumberDemo.swift +120 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputSearchDemo.swift +85 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputTextAreaDemo.swift +87 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/LoaderDemo.swift +73 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/LocalizeDemo.swift +235 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/NavigationDemo.swift +241 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PaginationDemo.swift +68 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PlaygroundData.swift +76 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupDisplayDemo.swift +175 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupNotifyDemo.swift +95 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupPromotionDemo.swift +67 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ProgressInfoDemo.swift +101 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RadioDemo.swift +64 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RatingDemo.swift +68 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SectionDemo.swift +83 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SkeletonDemo.swift +61 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SliderDemo.swift +90 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SnackBarDemo.swift +82 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepperDemo.swift +93 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepsDemo.swift +114 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SuggestActionDemo.swift +90 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwipeDemo.swift +107 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwitchDemo.swift +58 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TabViewDemo.swift +114 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TagDemo.swift +86 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ThemeDemo.swift +181 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TitleDemo.swift +104 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TooltipDemo.swift +118 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TypographyDemo.swift +87 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/UploaderDemo.swift +85 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SwiftUIDemoBrowserView.swift +53 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoModels.swift +15 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoRegistry.swift +73 -0
- package/package.json +6 -6
- package/publish.sh +554 -20
- package/scripts/gen-ios-color.mjs +136 -0
- package/CODE_OF_CONDUCT.md +0 -133
- package/CONTRIBUTING.md +0 -114
- package/LICENSE +0 -20
- package/android/build.gradle +0 -82
- package/android/gradle.properties +0 -5
- package/android/src/main/AndroidManifest.xml +0 -4
- package/android/src/main/java/com/momoplatform/nativekits/NativeKitsPackage.kt +0 -17
- package/android/src/main/java/com/momoplatform/nativekits/NativeKitsViewManager.kt +0 -20
- package/example/ios/Example/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -63
- package/example/ios/Example/ComponentDetail.swift +0 -35
- package/example/ios/Example/ComponentItem.swift +0 -24
- package/example/ios/Example/ComponentModel.swift +0 -33
- package/example/ios/Example/ContentView.swift +0 -53
- package/example/ios/Example/Example.entitlements +0 -10
- package/example/ios/Example/Foundation/ButtonDemo.swift +0 -80
- package/example/ios/Example/Foundation/Popup/ActionSheets.swift +0 -136
- package/example/ios/Example/Foundation/Popup/Floats.swift +0 -127
- package/example/ios/Example/Foundation/Popup/Popups.swift +0 -101
- package/example/ios/Example/Foundation/PopupDemo.swift +0 -366
- package/example/ios/Example/Foundation/TextInputDemo.swift +0 -31
- package/example/ios/Example/Foundation/TypographyDemo.swift +0 -53
- package/example/ios/Example/Foundation.swift +0 -26
- package/example/ios/Example/Info.plist +0 -18
- package/example/ios/Example/Library/SwipeableDemo.swift +0 -105
- package/example/ios/Example/Library.swift +0 -26
- package/example/ios/Example/Main.swift +0 -11
- package/example/ios/Example/Overview.swift +0 -20
- package/example/ios/Example/Resource/SFProText-Black.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Bold.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Heavy.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Light.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Medium.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Regular.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Semibold.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Thin.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Ultralight.ttf +0 -0
- package/example/ios/Example/Resource/foundation.json +0 -33
- package/example/ios/Example/Resource/library.json +0 -8
- package/example/ios/Example/Utils.swift +0 -30
- package/example/ios/Example/ViewModifier/DarkViewModifier.swift +0 -22
- package/example/ios/Example.xcodeproj/project.pbxproj +0 -570
- package/example/ios/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- package/example/ios/Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
- package/example/ios/Example.xcodeproj/project.xcworkspace/xcuserdata/wem.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/example/ios/Example.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
- package/example/ios/Example.xcworkspace/contents.xcworkspacedata +0 -10
- package/example/ios/Example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
- package/example/ios/Example.xcworkspace/xcuserdata/wem.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/example/ios/Example.xcworkspace/xcuserdata/wem.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +0 -6
- package/example/ios/Podfile +0 -6
- package/example/ios/Podfile.lock +0 -16
- package/example/ios/Pods/Local Podspecs/MoMoUIKits.podspec.json +0 -29
- package/example/ios/Pods/Manifest.lock +0 -16
- package/example/ios/Pods/Pods.xcodeproj/project.pbxproj +0 -661
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/MoMoUIKits.xcscheme +0 -58
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/Pods-Example.xcscheme +0 -58
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/xcschememanagement.plist +0 -25
- package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits-dummy.m +0 -5
- package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits-prefix.pch +0 -12
- package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits-umbrella.h +0 -16
- package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits.debug.xcconfig +0 -12
- package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits.modulemap +0 -6
- package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits.release.xcconfig +0 -12
- package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-acknowledgements.markdown +0 -3
- package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-acknowledgements.plist +0 -29
- package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-dummy.m +0 -5
- package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-umbrella.h +0 -16
- package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example.debug.xcconfig +0 -14
- package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example.modulemap +0 -6
- package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example.release.xcconfig +0 -14
- package/ios/Colors+Spacing/Radius.swift +0 -11
- package/ios/Popup/Utils++.swift +0 -163
- package/ios/Theme.md +0 -18
- /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/Background.colorset/Contents.json +0 -0
- /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/Border.colorset/Contents.json +0 -0
- /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/Card.colorset/Contents.json +0 -0
- /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/Contents.json +0 -0
- /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/Error.colorset/Contents.json +0 -0
- /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/Primary.colorset/Contents.json +0 -0
- /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/PrimaryDark.colorset/Contents.json +0 -0
- /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/PrimaryLight.colorset/Contents.json +0 -0
- /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/Secondary.colorset/Contents.json +0 -0
- /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/Success.colorset/Contents.json +0 -0
- /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/TextSecondary.colorset/Contents.json +0 -0
- /package/{example/ios/Example/Assets.xcassets → ios/Resources/MoMoUIKitsColors.xcassets}/Warning.colorset/Contents.json +0 -0
package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-default.colorset/Contents.json
ADDED
|
@@ -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
|
+
}
|
package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-disable.colorset/Contents.json
ADDED
|
@@ -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
|
+
}
|
package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-secondary.colorset/Contents.json
ADDED
|
@@ -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
|