@momo-kits/native-kits 0.162.2-debug → 0.162.2-sp.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/settings.local.json +55 -0
- package/ios/Application/Components.swift +34 -43
- package/ios/Application/FloatingButton.swift +10 -8
- package/ios/Application/Navigation/BottomTab/BottomTab.swift +102 -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 +151 -0
- package/ios/Application/Navigation/NavigationOptions.swift +109 -0
- package/ios/Application/Navigation/Navigator.swift +360 -0
- package/ios/Application/Navigation/Overplay/BottomSheet.swift +176 -0
- package/ios/Application/Navigation/Overplay/ModalScreen.swift +68 -0
- package/ios/Application/Navigation/Overplay/SnackBar.swift +144 -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/StackScreen.swift +449 -0
- package/ios/Avatar/Avatar.swift +193 -0
- package/ios/Badge/Badge.swift +11 -13
- package/ios/Badge/BadgeRibbon.swift +12 -19
- package/ios/BaselineView/BaselineView.swift +163 -0
- package/ios/Button/Button.swift +62 -23
- package/ios/Carousel/Carousel.swift +181 -0
- package/ios/Checkbox/Checkbox.swift +14 -12
- package/ios/Chip/Chip.swift +23 -9
- package/ios/Collapse/Collapse.swift +182 -0
- package/ios/Colors+Radius+Spacing/Colors.swift +1 -1
- package/ios/Colors+Radius+Spacing/Theme.swift +295 -0
- package/ios/DateTimePicker/DateTimePicker.swift +210 -0
- package/ios/DateTimePicker/DateTimePickerTypes.swift +55 -0
- package/ios/DateTimePicker/DateTimePickerUtils.swift +167 -0
- package/ios/DateTimePicker/WheelPicker.swift +161 -0
- package/ios/Divider/Divider.swift +16 -0
- package/ios/Icon/Icon.swift +6 -1
- package/ios/IconButton/IconButton.swift +112 -0
- package/ios/Information/Information.swift +151 -0
- package/ios/Input/Input.swift +42 -25
- package/ios/Input/InputPhoneNumber.swift +21 -19
- package/ios/Input/InputSearch.swift +101 -45
- package/ios/Input/InputTextArea.swift +67 -40
- package/ios/InputDropDown/InputDropDown.swift +198 -0
- package/ios/InputMoney/InputMoney.swift +335 -0
- package/ios/InputOTP/InputOTP.swift +210 -0
- package/ios/Loader/Loader.swift +113 -0
- package/ios/MoMoUIKits.podspec +5 -0
- package/ios/OTPKeyboard/KeyboardButton.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 +10 -12
- package/ios/Popup/PopupInput.swift +2 -6
- package/ios/Popup/PopupNotify.swift +219 -0
- package/ios/ProgressInfo/ProgressInfo.swift +294 -0
- package/ios/Radio/Radio.swift +70 -0
- package/ios/Rating/Rating.swift +82 -0
- package/ios/Skeleton/Skeleton.swift +99 -0
- package/ios/Slider/Slider.swift +237 -0
- package/ios/Stepper/Stepper.swift +220 -0
- package/ios/Steps/Steps.swift +451 -0
- package/ios/SuggestAction/SuggestAction.swift +97 -0
- package/ios/Swipeable/SwipeCell.swift +185 -0
- package/ios/Swipeable/SwipeCellModel.swift +21 -0
- package/ios/TabView/TabView.swift +530 -0
- package/ios/Tag/Tag.swift +98 -0
- package/ios/Template/TrustBanner/TrustBanner.swift +2 -0
- package/ios/Title/Title.swift +269 -0
- package/ios/Tooltip/Tooltip.swift +482 -0
- package/ios/Typography/Text.swift +77 -5
- package/ios/Typography/Typography.swift +9 -0
- package/ios/Uploader/Uploader.swift +183 -0
- package/ios/native-kits.podspec +58 -8
- package/ios-demo/MoMoUIKitsDemo.podspec +18 -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 +72 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/AnimatedHeaderDemo.swift +110 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/AvatarDemo.swift +93 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BadgeDemo.swift +269 -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 +100 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CarouselDemo.swift +126 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CheckboxDemo.swift +63 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ChipDemo.swift +20 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CollapseDemo.swift +93 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ContentView.swift +107 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DateTimePickerDemo.swift +124 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DividerDemo.swift +14 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/HeaderUserDemo.swift +49 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +261 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IconButtonDemo.swift +58 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ImageDemo.swift +78 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InformationDemo.swift +138 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDemo.swift +111 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDropDownDemo.swift +136 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputMoneyDemo.swift +107 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputOTPDemo.swift +73 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputPhoneNumberDemo.swift +100 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputSearchDemo.swift +32 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputTextAreaDemo.swift +57 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/LoaderDemo.swift +70 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/NavigationDemo.swift +227 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PaginationDemo.swift +72 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupDisplayDemo.swift +175 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupNotifyDemo.swift +121 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupPromotionDemo.swift +76 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ProgressInfoDemo.swift +89 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RadioDemo.swift +32 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RatingDemo.swift +56 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SkeletonDemo.swift +32 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SliderDemo.swift +150 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SnackBarDemo.swift +138 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepperDemo.swift +103 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepsDemo.swift +94 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SuggestActionDemo.swift +79 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwipeDemo.swift +152 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwitchDemo.swift +33 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TabViewDemo.swift +190 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TagDemo.swift +34 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ThemeDemo.swift +182 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TitleDemo.swift +109 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TooltipDemo.swift +187 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TypographyDemo.swift +87 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/UploaderDemo.swift +131 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SwiftUIDemoBrowserView.swift +50 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoModels.swift +15 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoRegistry.swift +73 -0
- package/package.json +1 -1
- package/publish.sh +50 -0
- package/scripts/gen-ios-color.mjs +136 -0
- package/build.gradle.kts +0 -11
- package/compose/build.gradle.kts +0 -186
- package/compose/build.gradle.kts.backup +0 -186
- package/compose/compose.podspec +0 -47
- package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +0 -6
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +0 -123
- package/compose/src/commonMain/composeResources/font/momosignature.otf +0 -0
- package/compose/src/commonMain/composeResources/font/momotrustdisplay.otf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_black.otf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_black.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_bold.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_heavy.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_light.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_medium.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_regular.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_semibold.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_thin.otf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_thin.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.otf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.ttf +0 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +0 -57
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +0 -109
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +0 -201
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +0 -222
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +0 -48
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +0 -86
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +0 -76
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +0 -76
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +0 -305
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +0 -33
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +0 -921
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +0 -121
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +0 -403
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +0 -69
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +0 -157
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +0 -85
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +0 -32
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +0 -340
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +0 -198
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +0 -357
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +0 -123
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -94
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +0 -136
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +0 -224
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +0 -543
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +0 -23
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +0 -76
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +0 -148
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +0 -188
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +0 -116
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +0 -452
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +0 -172
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +0 -255
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +0 -235
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +0 -233
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +0 -259
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +0 -241
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +0 -364
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +0 -108
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +0 -56
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +0 -41
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +0 -92
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +0 -40
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +0 -352
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +0 -103
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +0 -338
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +0 -70
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +0 -87
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +0 -17
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +0 -96
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +0 -348
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +0 -256
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +0 -494
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +0 -131
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +0 -215
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +0 -96
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +0 -531
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +0 -92
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +0 -135
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +0 -214
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +0 -590
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +0 -177
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +0 -192
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +0 -205
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +0 -29
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +0 -239
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +0 -191
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +0 -306
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +0 -12
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +0 -16
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +0 -188
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +0 -285
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +0 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +0 -35
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +0 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -57
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +0 -68
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +0 -11
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +0 -14
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +0 -50
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +0 -51
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +0 -253
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +0 -133
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +0 -104
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +0 -145
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +0 -345
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +0 -8
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +0 -556
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +0 -161
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +0 -243
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +0 -86
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +0 -187
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +0 -315
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +0 -80
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +0 -306
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +0 -34
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +0 -370
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +0 -131
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +0 -167
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +0 -72
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +0 -66
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +0 -1329
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +0 -70
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +0 -15
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +0 -105
- package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +0 -33
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +0 -186
- package/gradle/libs.versions.toml +0 -67
- package/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/gradle/wrapper/gradle-wrapper.properties +0 -8
- package/gradle.properties +0 -26
- package/gradlew +0 -252
- package/gradlew.bat +0 -94
- package/settings.gradle.kts +0 -64
|
@@ -77,10 +77,11 @@ public enum RibbonPosition {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
public struct BadgeRibbon: View {
|
|
80
|
+
@Environment(\.appTheme) private var theme
|
|
80
81
|
let position: RibbonPosition
|
|
81
82
|
let label: String
|
|
82
83
|
let isRound: Bool
|
|
83
|
-
let backgroundColor: Color
|
|
84
|
+
let backgroundColor: Color?
|
|
84
85
|
|
|
85
86
|
public init(
|
|
86
87
|
position: RibbonPosition = .topRight,
|
|
@@ -91,7 +92,7 @@ public struct BadgeRibbon: View {
|
|
|
91
92
|
self.position = position
|
|
92
93
|
self.label = label
|
|
93
94
|
self.isRound = isRound
|
|
94
|
-
self.backgroundColor = backgroundColor
|
|
95
|
+
self.backgroundColor = backgroundColor
|
|
95
96
|
}
|
|
96
97
|
|
|
97
98
|
private var rotation: Angle {
|
|
@@ -117,6 +118,8 @@ public struct BadgeRibbon: View {
|
|
|
117
118
|
}
|
|
118
119
|
|
|
119
120
|
public var body: some View {
|
|
121
|
+
let bgColor = backgroundColor ?? theme.colors.warning.primary
|
|
122
|
+
|
|
120
123
|
HStack(alignment: verticalAlignment, spacing: 0) {
|
|
121
124
|
if useUpTail {
|
|
122
125
|
upTail
|
|
@@ -125,21 +128,18 @@ public struct BadgeRibbon: View {
|
|
|
125
128
|
}
|
|
126
129
|
|
|
127
130
|
if isRound {
|
|
128
|
-
roundContent
|
|
131
|
+
roundContent(backgroundColor: bgColor)
|
|
129
132
|
} else {
|
|
130
|
-
skewContent
|
|
133
|
+
skewContent(backgroundColor: bgColor)
|
|
131
134
|
}
|
|
132
135
|
}
|
|
133
136
|
.frame(height: RibbonConstants.ribbonHeight)
|
|
134
137
|
.rotationEffect(rotation)
|
|
135
138
|
}
|
|
136
139
|
|
|
137
|
-
private
|
|
140
|
+
private func roundContent(backgroundColor: Color) -> some View {
|
|
138
141
|
HStack(spacing: 0) {
|
|
139
|
-
|
|
140
|
-
.font(.system(size: scaleSize(12), weight: .medium))
|
|
141
|
-
.foregroundColor(Colors.black01)
|
|
142
|
-
.lineLimit(1)
|
|
142
|
+
MomoText(label, typography: .labelXsMedium, color: Colors.black01, maxLines: 1)
|
|
143
143
|
.rotationEffect(rotation)
|
|
144
144
|
}
|
|
145
145
|
.frame(height: RibbonConstants.roundHeight)
|
|
@@ -155,12 +155,9 @@ public struct BadgeRibbon: View {
|
|
|
155
155
|
)
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
private
|
|
158
|
+
private func skewContent(backgroundColor: Color) -> some View {
|
|
159
159
|
HStack(spacing: 0) {
|
|
160
|
-
|
|
161
|
-
.font(.system(size: scaleSize(12), weight: .medium))
|
|
162
|
-
.foregroundColor(Colors.black01)
|
|
163
|
-
.lineLimit(1)
|
|
160
|
+
MomoText(label, typography: .labelXsMedium, color: Colors.black01, maxLines: 1)
|
|
164
161
|
.rotationEffect(rotation)
|
|
165
162
|
.frame(height: RibbonConstants.skewBodyHeight)
|
|
166
163
|
.padding(.horizontal, 8)
|
|
@@ -177,7 +174,6 @@ public struct BadgeRibbon: View {
|
|
|
177
174
|
)
|
|
178
175
|
.frame(width: RibbonConstants.headTailWidth, height: RibbonConstants.headTailHeight)
|
|
179
176
|
.rotationEffect(.degrees(180))
|
|
180
|
-
.offset(x: 1)
|
|
181
177
|
.clipped()
|
|
182
178
|
}
|
|
183
179
|
|
|
@@ -187,7 +183,6 @@ public struct BadgeRibbon: View {
|
|
|
187
183
|
placeholder: AnyView(Color.clear)
|
|
188
184
|
)
|
|
189
185
|
.frame(width: RibbonConstants.headTailWidth, height: RibbonConstants.headTailHeight)
|
|
190
|
-
.offset(x: 1)
|
|
191
186
|
.clipped()
|
|
192
187
|
}
|
|
193
188
|
|
|
@@ -197,7 +192,6 @@ public struct BadgeRibbon: View {
|
|
|
197
192
|
placeholder: AnyView(Color.clear)
|
|
198
193
|
)
|
|
199
194
|
.frame(width: RibbonConstants.skewTailWidth, height: RibbonConstants.skewTailHeight)
|
|
200
|
-
.offset(x: -2)
|
|
201
195
|
.clipped()
|
|
202
196
|
}
|
|
203
197
|
}
|
|
@@ -207,7 +201,7 @@ private struct RibbonConstants {
|
|
|
207
201
|
static let ribbonHeight: CGFloat = 20
|
|
208
202
|
static let roundHeight: CGFloat = 16
|
|
209
203
|
static let skewBodyHeight: CGFloat = 16
|
|
210
|
-
static let roundRightRadius: CGFloat =
|
|
204
|
+
static let roundRightRadius: CGFloat = 12
|
|
211
205
|
static let roundPaddingEnd: CGFloat = 6
|
|
212
206
|
static let skewTailWidth: CGFloat = 8
|
|
213
207
|
static let skewTailHeight: CGFloat = 16
|
|
@@ -239,4 +233,3 @@ struct BadgeRibbon_Previews: PreviewProvider {
|
|
|
239
233
|
}
|
|
240
234
|
}
|
|
241
235
|
#endif
|
|
242
|
-
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
|
|
3
|
+
public struct BaselineView: View {
|
|
4
|
+
private let enabled: Bool
|
|
5
|
+
|
|
6
|
+
public init(enabled: Bool = true) {
|
|
7
|
+
self.enabled = enabled
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
public var body: some View {
|
|
11
|
+
if enabled {
|
|
12
|
+
GeometryReader { geometry in
|
|
13
|
+
let topInset = geometry.safeAreaInsets.top
|
|
14
|
+
let bottomInset = min(geometry.safeAreaInsets.bottom, 21)
|
|
15
|
+
|
|
16
|
+
ZStack(alignment: .topLeading) {
|
|
17
|
+
dangerZones(topInset: topInset, bottomInset: bottomInset)
|
|
18
|
+
guideLines(
|
|
19
|
+
topInset: topInset,
|
|
20
|
+
bottomInset: bottomInset,
|
|
21
|
+
width: geometry.size.width
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
|
25
|
+
.ignoresSafeArea()
|
|
26
|
+
.allowsHitTesting(false)
|
|
27
|
+
.accessibilityHidden(true)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private func dangerZones(topInset: CGFloat, bottomInset: CGFloat) -> some View {
|
|
33
|
+
let safeBackground = Color.red.opacity(0.15)
|
|
34
|
+
|
|
35
|
+
return ZStack(alignment: .topLeading) {
|
|
36
|
+
safeBackground
|
|
37
|
+
.frame(maxWidth: .infinity)
|
|
38
|
+
.frame(height: topInset)
|
|
39
|
+
|
|
40
|
+
HStack(spacing: 0) {
|
|
41
|
+
safeBackground
|
|
42
|
+
.frame(width: 12)
|
|
43
|
+
Spacer(minLength: 0)
|
|
44
|
+
safeBackground
|
|
45
|
+
.frame(width: 12)
|
|
46
|
+
}
|
|
47
|
+
.padding(.top, topInset)
|
|
48
|
+
.padding(.bottom, bottomInset)
|
|
49
|
+
|
|
50
|
+
VStack(spacing: 0) {
|
|
51
|
+
Spacer(minLength: 0)
|
|
52
|
+
safeBackground
|
|
53
|
+
.frame(maxWidth: .infinity)
|
|
54
|
+
.frame(height: bottomInset)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private func guideLines(topInset: CGFloat, bottomInset: CGFloat, width: CGFloat) -> some View {
|
|
60
|
+
ZStack(alignment: .topLeading) {
|
|
61
|
+
baselineLine(isDotted: false, color: Color(hex: 0xE400FF))
|
|
62
|
+
.offset(y: topInset)
|
|
63
|
+
|
|
64
|
+
baselineLine(color: Color(hex: 0xE400FF))
|
|
65
|
+
.offset(y: topInset + 52)
|
|
66
|
+
|
|
67
|
+
baselineLine(color: Color(hex: 0xE400FF))
|
|
68
|
+
.offset(y: topInset + 104)
|
|
69
|
+
|
|
70
|
+
bottomLine(bottomInset: bottomInset + 64, color: Color(hex: 0xE400FF))
|
|
71
|
+
|
|
72
|
+
bottomLine(bottomInset: bottomInset, isDotted: false, color: Color(hex: 0xE400FF))
|
|
73
|
+
|
|
74
|
+
baselineLine(orientation: .vertical, isDotted: false, color: Color(hex: 0xE400FF))
|
|
75
|
+
.offset(x: 12)
|
|
76
|
+
|
|
77
|
+
baselineLine(orientation: .vertical, isDotted: false, color: Color(hex: 0xE400FF))
|
|
78
|
+
.offset(x: width - 12)
|
|
79
|
+
|
|
80
|
+
baselineLine(color: Color(hex: 0xFF7A00))
|
|
81
|
+
.offset(y: topInset + 26)
|
|
82
|
+
|
|
83
|
+
bottomLine(bottomInset: bottomInset + 56, color: Color(hex: 0xFFCC00))
|
|
84
|
+
|
|
85
|
+
bottomLine(bottomInset: bottomInset + 8, color: Color(hex: 0xFFCC00))
|
|
86
|
+
|
|
87
|
+
baselineLine(orientation: .vertical, color: Color(hex: 0x00C520))
|
|
88
|
+
.frame(height: 52)
|
|
89
|
+
.offset(x: 40, y: topInset)
|
|
90
|
+
|
|
91
|
+
baselineLine(orientation: .vertical, color: Color(hex: 0x00C520))
|
|
92
|
+
.frame(height: 52)
|
|
93
|
+
.offset(x: 48, y: topInset)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private func bottomLine(
|
|
98
|
+
bottomInset: CGFloat,
|
|
99
|
+
isDotted: Bool = true,
|
|
100
|
+
color: Color
|
|
101
|
+
) -> some View {
|
|
102
|
+
VStack(spacing: 0) {
|
|
103
|
+
Spacer(minLength: 0)
|
|
104
|
+
baselineLine(isDotted: isDotted, color: color)
|
|
105
|
+
.padding(.bottom, bottomInset)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private func baselineLine(
|
|
110
|
+
orientation: BaselineOrientation = .horizontal,
|
|
111
|
+
isDotted: Bool = true,
|
|
112
|
+
color: Color
|
|
113
|
+
) -> some View {
|
|
114
|
+
BaselineLineShape(orientation: orientation)
|
|
115
|
+
.stroke(
|
|
116
|
+
color,
|
|
117
|
+
style: StrokeStyle(
|
|
118
|
+
lineWidth: 1,
|
|
119
|
+
lineCap: .round,
|
|
120
|
+
dash: isDotted ? [8, 8] : []
|
|
121
|
+
)
|
|
122
|
+
)
|
|
123
|
+
.frame(
|
|
124
|
+
maxWidth: orientation == .horizontal ? .infinity : 1,
|
|
125
|
+
maxHeight: orientation == .vertical ? .infinity : 1
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
public enum BaselineOrientation: Sendable {
|
|
131
|
+
case horizontal
|
|
132
|
+
case vertical
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private struct BaselineLineShape: Shape {
|
|
136
|
+
let orientation: BaselineOrientation
|
|
137
|
+
|
|
138
|
+
func path(in rect: CGRect) -> Path {
|
|
139
|
+
var path = Path()
|
|
140
|
+
|
|
141
|
+
switch orientation {
|
|
142
|
+
case .horizontal:
|
|
143
|
+
path.move(to: CGPoint(x: rect.minX, y: rect.midY))
|
|
144
|
+
path.addLine(to: CGPoint(x: rect.maxX, y: rect.midY))
|
|
145
|
+
case .vertical:
|
|
146
|
+
path.move(to: CGPoint(x: rect.midX, y: rect.minY))
|
|
147
|
+
path.addLine(to: CGPoint(x: rect.midX, y: rect.maxY))
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return path
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
#if DEBUG
|
|
155
|
+
struct BaselineView_Previews: PreviewProvider {
|
|
156
|
+
static var previews: some View {
|
|
157
|
+
ZStack {
|
|
158
|
+
Colors.black01
|
|
159
|
+
BaselineView()
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
#endif
|
package/ios/Button/Button.swift
CHANGED
|
@@ -31,33 +31,45 @@ public struct ButtonStyleData {
|
|
|
31
31
|
|
|
32
32
|
public extension ButtonType {
|
|
33
33
|
func backgroundColor(loading: Bool) -> Color {
|
|
34
|
+
backgroundColor(loading: loading, theme: defaultTheme)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
func backgroundColor(loading: Bool, theme: Theme) -> Color {
|
|
34
38
|
switch self {
|
|
35
|
-
case .disabled: return
|
|
36
|
-
case .primary: return
|
|
37
|
-
case .secondary: return
|
|
38
|
-
case .outline: return
|
|
39
|
-
case .tonal: return
|
|
40
|
-
case .danger: return
|
|
39
|
+
case .disabled: return theme.colors.background.disable.opacity(loading ? 0.75 : 1)
|
|
40
|
+
case .primary: return theme.colors.primary.opacity(loading ? 0.75 : 1)
|
|
41
|
+
case .secondary: return theme.colors.background.surface.opacity(loading ? 0.75 : 1)
|
|
42
|
+
case .outline: return theme.colors.background.surface.opacity(loading ? 0.75 : 1)
|
|
43
|
+
case .tonal: return theme.colors.background.tonal.opacity(loading ? 0.75 : 1)
|
|
44
|
+
case .danger: return theme.colors.error.primary.opacity(loading ? 0.75 : 1)
|
|
41
45
|
case .text: return .clear
|
|
42
46
|
}
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
func contentColor(loading: Bool) -> Color {
|
|
50
|
+
contentColor(loading: loading, theme: defaultTheme)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
func contentColor(loading: Bool, theme: Theme) -> Color {
|
|
46
54
|
switch self {
|
|
47
|
-
case .disabled: return
|
|
55
|
+
case .disabled: return theme.colors.text.disable.opacity(loading ? 0.75 : 1)
|
|
48
56
|
case .primary: return Colors.black01
|
|
49
|
-
case .secondary: return
|
|
50
|
-
case .outline: return
|
|
51
|
-
case .tonal: return
|
|
57
|
+
case .secondary: return theme.colors.text.default
|
|
58
|
+
case .outline: return theme.colors.primary
|
|
59
|
+
case .tonal: return theme.colors.primary
|
|
52
60
|
case .danger: return Colors.black01
|
|
53
|
-
case .text: return
|
|
61
|
+
case .text: return theme.colors.primary
|
|
54
62
|
}
|
|
55
63
|
}
|
|
56
64
|
|
|
57
65
|
var borderColor: Color? {
|
|
66
|
+
borderColor(theme: defaultTheme)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
func borderColor(theme: Theme) -> Color? {
|
|
58
70
|
switch self {
|
|
59
|
-
case .outline: return
|
|
60
|
-
case .secondary: return
|
|
71
|
+
case .outline: return theme.colors.primary
|
|
72
|
+
case .secondary: return theme.colors.border.default
|
|
61
73
|
default: return nil
|
|
62
74
|
}
|
|
63
75
|
}
|
|
@@ -117,6 +129,7 @@ extension ButtonSize {
|
|
|
117
129
|
}
|
|
118
130
|
|
|
119
131
|
public struct Button: View {
|
|
132
|
+
@Environment(\.appTheme) private var theme
|
|
120
133
|
var title: String
|
|
121
134
|
var action: () -> Void
|
|
122
135
|
var type: ButtonType
|
|
@@ -125,6 +138,7 @@ public struct Button: View {
|
|
|
125
138
|
var iconRight: AnyView?
|
|
126
139
|
var isFull: Bool
|
|
127
140
|
var loading: Bool
|
|
141
|
+
var useTintColor: Bool
|
|
128
142
|
|
|
129
143
|
public init(
|
|
130
144
|
title: String = "",
|
|
@@ -134,7 +148,8 @@ public struct Button: View {
|
|
|
134
148
|
iconLeft: AnyView? = nil,
|
|
135
149
|
iconRight: AnyView? = nil,
|
|
136
150
|
isFull: Bool = true,
|
|
137
|
-
loading: Bool = false
|
|
151
|
+
loading: Bool = false,
|
|
152
|
+
useTintColor: Bool = true
|
|
138
153
|
) {
|
|
139
154
|
self.title = title
|
|
140
155
|
self.action = action
|
|
@@ -144,6 +159,7 @@ public struct Button: View {
|
|
|
144
159
|
self.iconRight = iconRight
|
|
145
160
|
self.isFull = isFull
|
|
146
161
|
self.loading = loading
|
|
162
|
+
self.useTintColor = useTintColor
|
|
147
163
|
}
|
|
148
164
|
|
|
149
165
|
private func shouldLoadingOnLeft(_ left: AnyView?, _ right: AnyView?) -> Bool {
|
|
@@ -160,14 +176,15 @@ public struct Button: View {
|
|
|
160
176
|
|
|
161
177
|
public var body: some View {
|
|
162
178
|
let loadingOnLeft = shouldLoadingOnLeft(iconLeft, iconRight)
|
|
179
|
+
let isEnabled = type != .disabled && !loading
|
|
163
180
|
|
|
164
|
-
let bg = type.backgroundColor(loading: loading)
|
|
165
|
-
let fg = type.contentColor(loading: loading)
|
|
166
|
-
let border = type.borderColor
|
|
181
|
+
let bg = type.backgroundColor(loading: loading, theme: theme)
|
|
182
|
+
let fg = type.contentColor(loading: loading, theme: theme)
|
|
183
|
+
let border = type.borderColor(theme: theme)
|
|
167
184
|
let borderWidth = type.borderWidth
|
|
168
185
|
|
|
169
186
|
SwiftUI.Button(action: {
|
|
170
|
-
if
|
|
187
|
+
if isEnabled {
|
|
171
188
|
action()
|
|
172
189
|
}
|
|
173
190
|
}) {
|
|
@@ -178,7 +195,7 @@ public struct Button: View {
|
|
|
178
195
|
.colorMultiply(fg)
|
|
179
196
|
|
|
180
197
|
} else if let iconLeft = iconLeft {
|
|
181
|
-
iconLeft
|
|
198
|
+
tintedIcon(iconLeft, color: fg)
|
|
182
199
|
}
|
|
183
200
|
|
|
184
201
|
MomoText(title, typography: size.typographyStyle, color: fg)
|
|
@@ -191,7 +208,7 @@ public struct Button: View {
|
|
|
191
208
|
.colorMultiply(fg)
|
|
192
209
|
|
|
193
210
|
} else if let iconRight = iconRight {
|
|
194
|
-
iconRight
|
|
211
|
+
tintedIcon(iconRight, color: fg)
|
|
195
212
|
}
|
|
196
213
|
}
|
|
197
214
|
.frame(maxWidth: isFull ? .infinity : nil)
|
|
@@ -200,11 +217,33 @@ public struct Button: View {
|
|
|
200
217
|
.background(bg)
|
|
201
218
|
.overlay(
|
|
202
219
|
RoundedRectangle(cornerRadius: size.radius)
|
|
203
|
-
.
|
|
220
|
+
.strokeBorder(border ?? .clear, lineWidth: border != nil ? borderWidth : 0)
|
|
204
221
|
)
|
|
205
222
|
.clipShape(RoundedRectangle(cornerRadius: size.radius))
|
|
206
|
-
.opacity(loading ? 0.75 : 1)
|
|
207
223
|
}
|
|
208
|
-
.
|
|
224
|
+
.buttonStyle(ButtonPressFeedbackStyle(isEnabled: isEnabled))
|
|
225
|
+
.disabled(!isEnabled)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
@ViewBuilder
|
|
229
|
+
private func tintedIcon(_ icon: AnyView, color: Color) -> some View {
|
|
230
|
+
if useTintColor {
|
|
231
|
+
icon
|
|
232
|
+
.frame(width: size.iconSize, height: size.iconSize)
|
|
233
|
+
.colorMultiply(color)
|
|
234
|
+
} else {
|
|
235
|
+
icon
|
|
236
|
+
.frame(width: size.iconSize, height: size.iconSize)
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
private struct ButtonPressFeedbackStyle: ButtonStyle {
|
|
242
|
+
let isEnabled: Bool
|
|
243
|
+
|
|
244
|
+
func makeBody(configuration: Configuration) -> some View {
|
|
245
|
+
configuration.label
|
|
246
|
+
.opacity(configuration.isPressed && isEnabled ? 0.5 : 1)
|
|
247
|
+
.animation(.easeInOut(duration: 0.1), value: configuration.isPressed)
|
|
209
248
|
}
|
|
210
249
|
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import Combine
|
|
2
|
+
import SwiftUI
|
|
3
|
+
|
|
4
|
+
/// Native SwiftUI port of the Compose `Carousel` component.
|
|
5
|
+
///
|
|
6
|
+
/// Mirrors the Compose API: a paging horizontal carousel driven by an
|
|
7
|
+
/// `itemCount` and a `content` builder that receives the real (modulo) index.
|
|
8
|
+
/// Supports infinite `loop`, `autoplay` with a configurable interval,
|
|
9
|
+
/// inactive-slide `opacity`/`scale` effects, optional `contentPadding`,
|
|
10
|
+
/// snap behavior, and scroll enable/disable. Snap / scroll-index callbacks
|
|
11
|
+
/// report the real item index.
|
|
12
|
+
///
|
|
13
|
+
/// Available iOS 14+ (uses a custom paging ScrollView so behavior is identical
|
|
14
|
+
/// across versions and supports the loop virtualization + transform effects
|
|
15
|
+
/// that `TabView(.page)` cannot express).
|
|
16
|
+
public struct Carousel<Content: View>: View {
|
|
17
|
+
// MARK: Lifecycle
|
|
18
|
+
|
|
19
|
+
public init(
|
|
20
|
+
itemCount: Int,
|
|
21
|
+
loop: Bool = false,
|
|
22
|
+
autoplay: Bool = false,
|
|
23
|
+
autoplayInterval: TimeInterval = 3.0,
|
|
24
|
+
enableSnap: Bool = true,
|
|
25
|
+
scrollEnabled: Bool = true,
|
|
26
|
+
inactiveSlideOpacity: Double = 1.0,
|
|
27
|
+
inactiveSlideScale: Double = 1.0,
|
|
28
|
+
contentPadding: CGFloat = 0,
|
|
29
|
+
onSnapToItem: @escaping (Int) -> Void = { _ in },
|
|
30
|
+
onScrollIndexChanged: @escaping (Int) -> Void = { _ in },
|
|
31
|
+
@ViewBuilder content: @escaping (_ index: Int) -> Content
|
|
32
|
+
) {
|
|
33
|
+
self.itemCount = itemCount
|
|
34
|
+
self.loop = loop
|
|
35
|
+
self.autoplay = autoplay
|
|
36
|
+
self.autoplayInterval = autoplayInterval
|
|
37
|
+
self.enableSnap = enableSnap
|
|
38
|
+
self.scrollEnabled = scrollEnabled
|
|
39
|
+
self.inactiveSlideOpacity = inactiveSlideOpacity
|
|
40
|
+
self.inactiveSlideScale = inactiveSlideScale
|
|
41
|
+
self.contentPadding = contentPadding
|
|
42
|
+
self.onSnapToItem = onSnapToItem
|
|
43
|
+
self.onScrollIndexChanged = onScrollIndexChanged
|
|
44
|
+
self.content = content
|
|
45
|
+
|
|
46
|
+
let virtual = loop ? itemCount * 1000 : itemCount
|
|
47
|
+
let start = loop ? (virtual / 2) - ((virtual / 2) % max(itemCount, 1)) : 0
|
|
48
|
+
self.virtualPageCount = virtual
|
|
49
|
+
_currentPage = State(initialValue: start)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// MARK: Public
|
|
53
|
+
|
|
54
|
+
public var body: some View {
|
|
55
|
+
if itemCount <= 0 {
|
|
56
|
+
EmptyView()
|
|
57
|
+
} else {
|
|
58
|
+
GeometryReader { geo in
|
|
59
|
+
let pageWidth = max(geo.size.width - contentPadding * 2, 1)
|
|
60
|
+
carouselContent(pageWidth: pageWidth, viewportWidth: geo.size.width)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// MARK: Private
|
|
66
|
+
|
|
67
|
+
private let itemCount: Int
|
|
68
|
+
private let loop: Bool
|
|
69
|
+
private let autoplay: Bool
|
|
70
|
+
private let autoplayInterval: TimeInterval
|
|
71
|
+
private let enableSnap: Bool
|
|
72
|
+
private let scrollEnabled: Bool
|
|
73
|
+
private let inactiveSlideOpacity: Double
|
|
74
|
+
private let inactiveSlideScale: Double
|
|
75
|
+
private let contentPadding: CGFloat
|
|
76
|
+
private let onSnapToItem: (Int) -> Void
|
|
77
|
+
private let onScrollIndexChanged: (Int) -> Void
|
|
78
|
+
private let content: (Int) -> Content
|
|
79
|
+
|
|
80
|
+
private let virtualPageCount: Int
|
|
81
|
+
|
|
82
|
+
@State private var currentPage: Int
|
|
83
|
+
@State private var dragOffset: CGFloat = 0
|
|
84
|
+
@State private var isDragging: Bool = false
|
|
85
|
+
@State private var autoplayTick: Int = 0
|
|
86
|
+
|
|
87
|
+
private func realIndex(_ page: Int) -> Int {
|
|
88
|
+
((page % itemCount) + itemCount) % itemCount
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@ViewBuilder
|
|
92
|
+
private func carouselContent(pageWidth: CGFloat, viewportWidth: CGFloat) -> some View {
|
|
93
|
+
let step = pageWidth
|
|
94
|
+
// Offset so the current page is centered within the viewport padding.
|
|
95
|
+
let baseOffset = -CGFloat(currentPage) * step + contentPadding
|
|
96
|
+
|
|
97
|
+
ZStack {
|
|
98
|
+
HStack(spacing: 0) {
|
|
99
|
+
ForEach(0 ..< virtualPageCount, id: \.self) { page in
|
|
100
|
+
slide(page: page, step: step, viewportWidth: viewportWidth)
|
|
101
|
+
.frame(width: pageWidth)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
.offset(x: baseOffset + dragOffset)
|
|
105
|
+
.animation(isDragging ? nil : .easeInOut(duration: 0.25), value: currentPage)
|
|
106
|
+
.frame(width: viewportWidth, alignment: .leading)
|
|
107
|
+
.contentShape(Rectangle())
|
|
108
|
+
.gesture(scrollEnabled ? dragGesture(step: step) : nil)
|
|
109
|
+
}
|
|
110
|
+
.frame(width: viewportWidth)
|
|
111
|
+
.clipped()
|
|
112
|
+
.onReceive(autoplayTimer) { _ in
|
|
113
|
+
guard autoplay, itemCount > 1, !isDragging else { return }
|
|
114
|
+
advance()
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
@ViewBuilder
|
|
119
|
+
private func slide(page: Int, step: CGFloat, viewportWidth: CGFloat) -> some View {
|
|
120
|
+
// Fractional offset of this page from the current page (incl. drag).
|
|
121
|
+
let dragFraction = step > 0 ? -dragOffset / step : 0
|
|
122
|
+
let pageOffset = abs(CGFloat(currentPage - page) + dragFraction)
|
|
123
|
+
let isActive = pageOffset < 0.5
|
|
124
|
+
let scale = isActive ? 1.0 : inactiveSlideScale
|
|
125
|
+
let alpha = isActive ? 1.0 : inactiveSlideOpacity
|
|
126
|
+
|
|
127
|
+
content(realIndex(page))
|
|
128
|
+
.scaleEffect(scale)
|
|
129
|
+
.opacity(alpha)
|
|
130
|
+
.animation(.easeInOut(duration: 0.15), value: isActive)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
private func dragGesture(step: CGFloat) -> some Gesture {
|
|
134
|
+
DragGesture(minimumDistance: 5)
|
|
135
|
+
.onChanged { value in
|
|
136
|
+
isDragging = true
|
|
137
|
+
dragOffset = value.translation.width
|
|
138
|
+
}
|
|
139
|
+
.onEnded { value in
|
|
140
|
+
isDragging = false
|
|
141
|
+
let predicted = value.predictedEndTranslation.width
|
|
142
|
+
let threshold = step / 4
|
|
143
|
+
var target = currentPage
|
|
144
|
+
if enableSnap {
|
|
145
|
+
if predicted < -threshold {
|
|
146
|
+
target = min(currentPage + 1, virtualPageCount - 1)
|
|
147
|
+
} else if predicted > threshold {
|
|
148
|
+
target = max(currentPage - 1, 0)
|
|
149
|
+
}
|
|
150
|
+
} else {
|
|
151
|
+
// Free scroll still settles to nearest page boundary.
|
|
152
|
+
let moved = step > 0 ? Int((-dragOffset / step).rounded()) : 0
|
|
153
|
+
target = min(max(currentPage + moved, 0), virtualPageCount - 1)
|
|
154
|
+
}
|
|
155
|
+
dragOffset = 0
|
|
156
|
+
setPage(target)
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private func advance() {
|
|
161
|
+
let next = currentPage + 1
|
|
162
|
+
if next < virtualPageCount {
|
|
163
|
+
setPage(next)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private func setPage(_ page: Int) {
|
|
168
|
+
let clamped = min(max(page, 0), virtualPageCount - 1)
|
|
169
|
+
let changed = clamped != currentPage
|
|
170
|
+
currentPage = clamped
|
|
171
|
+
if changed {
|
|
172
|
+
let real = realIndex(clamped)
|
|
173
|
+
onSnapToItem(real)
|
|
174
|
+
onScrollIndexChanged(real)
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private var autoplayTimer: Publishers.Autoconnect<Timer.TimerPublisher> {
|
|
179
|
+
Timer.publish(every: autoplayInterval, on: .main, in: .common).autoconnect()
|
|
180
|
+
}
|
|
181
|
+
}
|
|
@@ -2,6 +2,7 @@ import Foundation
|
|
|
2
2
|
import SwiftUI
|
|
3
3
|
|
|
4
4
|
public struct Checkbox: View{
|
|
5
|
+
@Environment(\.appTheme) private var theme
|
|
5
6
|
@Binding var checked: Bool
|
|
6
7
|
var disabled: Bool
|
|
7
8
|
var onChange: ((Bool)->Void)?
|
|
@@ -37,11 +38,11 @@ public struct Checkbox: View{
|
|
|
37
38
|
)
|
|
38
39
|
|
|
39
40
|
if checked {
|
|
40
|
-
Image(systemName: indeterminate ? "minus
|
|
41
|
+
Image(systemName: indeterminate ? "minus" : "checkmark")
|
|
41
42
|
.resizable()
|
|
42
|
-
.
|
|
43
|
-
.
|
|
44
|
-
.frame(width:
|
|
43
|
+
.scaledToFit()
|
|
44
|
+
.foregroundColor(Colors.black01)
|
|
45
|
+
.frame(width: 12, height: 12)
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
48
|
|
|
@@ -53,27 +54,28 @@ public struct Checkbox: View{
|
|
|
53
54
|
|
|
54
55
|
// Title
|
|
55
56
|
if !title.isEmpty {
|
|
56
|
-
|
|
57
|
-
.font(.description1)
|
|
57
|
+
MomoText(title, typography: .descriptionDefaultRegular)
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
private var borderColor: Color {
|
|
63
|
-
if disabled {
|
|
64
|
-
return
|
|
63
|
+
if disabled && checked {
|
|
64
|
+
return theme.colors.background.tonal
|
|
65
|
+
} else if disabled {
|
|
66
|
+
return theme.colors.border.disable
|
|
65
67
|
} else if checked {
|
|
66
|
-
return
|
|
68
|
+
return theme.colors.primary
|
|
67
69
|
} else {
|
|
68
|
-
return
|
|
70
|
+
return theme.colors.text.default
|
|
69
71
|
}
|
|
70
72
|
}
|
|
71
73
|
|
|
72
74
|
private var backgroundColor: Color {
|
|
73
75
|
if disabled && checked {
|
|
74
|
-
return
|
|
76
|
+
return theme.colors.background.tonal
|
|
75
77
|
} else if checked {
|
|
76
|
-
return
|
|
78
|
+
return theme.colors.primary
|
|
77
79
|
} else {
|
|
78
80
|
return Color.clear
|
|
79
81
|
}
|