@momo-kits/native-kits 0.162.2-beta.1 → 0.162.2-sp.1-debug
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +55 -0
- package/build.gradle.kts +11 -0
- package/compose/build.gradle.kts +186 -0
- package/compose/build.gradle.kts.backup +186 -0
- package/compose/compose.podspec +47 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +6 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +123 -0
- 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 +57 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +109 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +201 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +222 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +48 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +86 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +76 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +76 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +305 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +33 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +921 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +121 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +403 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +69 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +157 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +85 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +32 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +340 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +198 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +357 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +123 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +94 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +136 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +224 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +543 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +23 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +76 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +148 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +188 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +116 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +452 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +172 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +255 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +235 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +233 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +259 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +241 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +364 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +108 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +56 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +41 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +92 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +40 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +352 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +103 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +338 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +70 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +87 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +17 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +96 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +348 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +256 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +494 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +131 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +215 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +96 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +531 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +92 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +135 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +214 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +590 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +177 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +192 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +205 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +29 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +239 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +191 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +306 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +12 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +16 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +188 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +285 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +2 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +35 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +2 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +57 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +68 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +11 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +14 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +50 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +51 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +253 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +133 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +104 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +145 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +345 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +8 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +556 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +161 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +243 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +86 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +187 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +315 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +80 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +306 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +34 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +370 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +131 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +167 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +72 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +66 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +1329 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +70 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +15 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +105 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +33 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +186 -0
- package/gradle/libs.versions.toml +67 -0
- package/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/gradle/wrapper/gradle-wrapper.properties +8 -0
- package/gradle.properties +26 -0
- package/gradlew +252 -0
- package/gradlew.bat +94 -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 +86 -24
- package/ios/Typography/Typography.swift +31 -6
- package/ios/Uploader/Uploader.swift +183 -0
- package/ios/native-kits.podspec +58 -8
- package/ios-demo/MoMoUIKitsDemo.podspec +18 -0
- package/ios-demo/README.md +120 -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/local.properties +8 -0
- package/package.json +1 -1
- package/publish.sh +50 -0
- package/scripts/gen-ios-color.mjs +136 -0
- package/settings.gradle.kts +64 -0
- package/example/ios/Example.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/Example.xcscheme +0 -32
- package/example/ios/Example.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
- package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/WorkspaceSettings.xcsettings +0 -16
- package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +0 -6
- package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +0 -5
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/MoMoUIKits.xcscheme +0 -58
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/Pods-Example.xcscheme +0 -58
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SDWebImage.xcscheme +0 -58
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SDWebImageSwiftUI.xcscheme +0 -58
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SkeletonUI.xcscheme +0 -58
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/lottie-ios-LottiePrivacyInfo.xcscheme +0 -58
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/lottie-ios.xcscheme +0 -58
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +0 -60
- package/ios/Typography/MomoFontScale.swift +0 -36
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
//
|
|
2
|
+
// NavigationContainer.swift
|
|
3
|
+
// MoMoUIKits
|
|
4
|
+
//
|
|
5
|
+
// SwiftUI mirror of Compose's NavigationContainer.
|
|
6
|
+
// Wraps NavigationStack, injects Navigator into the environment, and renders
|
|
7
|
+
// every registered screen inside `Screen(options)` chrome — same auto-wrap
|
|
8
|
+
// behavior as Compose's StackScreen.
|
|
9
|
+
//
|
|
10
|
+
|
|
11
|
+
import SwiftUI
|
|
12
|
+
|
|
13
|
+
@available(iOS 16.0, *)
|
|
14
|
+
public struct NavigationContainer<Initial: View>: View {
|
|
15
|
+
@StateObject private var navigator: Navigator
|
|
16
|
+
|
|
17
|
+
private let setNavigator: ((Navigator) -> Void)?
|
|
18
|
+
|
|
19
|
+
public init(
|
|
20
|
+
initialScreenName: String = "",
|
|
21
|
+
@ViewBuilder initialScreen: @escaping () -> Initial,
|
|
22
|
+
options: NavigationOptions? = nil,
|
|
23
|
+
setNavigator: ((Navigator) -> Void)? = nil
|
|
24
|
+
) {
|
|
25
|
+
let nav = Navigator(
|
|
26
|
+
initialScreenName: initialScreenName.isEmpty ? (options?.screenName ?? "") : initialScreenName,
|
|
27
|
+
initialContent: { AnyView(initialScreen()) },
|
|
28
|
+
options: options
|
|
29
|
+
)
|
|
30
|
+
_navigator = StateObject(wrappedValue: nav)
|
|
31
|
+
self.setNavigator = setNavigator
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public var body: some View {
|
|
35
|
+
NavigationStack(path: $navigator.path) {
|
|
36
|
+
screenView(for: navigator.rootRoute)
|
|
37
|
+
.navigationDestination(for: DynamicScreenRoute.self) { route in
|
|
38
|
+
screenView(for: route)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
.environmentObject(navigator)
|
|
42
|
+
.fullScreenCover(item: $navigator.presented) { route in
|
|
43
|
+
screenView(forDialog: route)
|
|
44
|
+
.environmentObject(navigator)
|
|
45
|
+
}
|
|
46
|
+
.overlay {
|
|
47
|
+
if let item = navigator.overplay {
|
|
48
|
+
OverplayHost(item: item)
|
|
49
|
+
.environmentObject(navigator)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
.onAppear { setNavigator?(navigator) }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@ViewBuilder
|
|
56
|
+
private func screenView(for route: DynamicScreenRoute) -> some View {
|
|
57
|
+
if let screen = DynamicScreenRegistry.shared.getScreen(id: route.id) {
|
|
58
|
+
ScreenHost(screen: screen, navigator: navigator)
|
|
59
|
+
.navigationBarBackButtonHidden(true)
|
|
60
|
+
} else {
|
|
61
|
+
EmptyView()
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@ViewBuilder
|
|
66
|
+
private func screenView(forDialog route: DynamicDialogRoute) -> some View {
|
|
67
|
+
if let screen = DynamicScreenRegistry.shared.getScreen(id: route.id) {
|
|
68
|
+
ScreenHost(screen: screen, navigator: navigator)
|
|
69
|
+
} else {
|
|
70
|
+
EmptyView()
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// MARK: - ScreenHost
|
|
76
|
+
|
|
77
|
+
@available(iOS 16.0, *)
|
|
78
|
+
private struct ScreenHost: View {
|
|
79
|
+
let screen: DynamicScreen
|
|
80
|
+
let navigator: Navigator
|
|
81
|
+
|
|
82
|
+
var body: some View {
|
|
83
|
+
let options = screen.options ?? NavigationOptions()
|
|
84
|
+
StackScreen(
|
|
85
|
+
backgroundColor: options.backgroundColor,
|
|
86
|
+
headerTransparent: options.headerTransparent,
|
|
87
|
+
fullScreenContent: options.fullScreenContent,
|
|
88
|
+
tintColor: options.tintColor ?? Colors.black17,
|
|
89
|
+
isBack: !options.hiddenBack,
|
|
90
|
+
headerType: options.headerType,
|
|
91
|
+
useAnimated: options.useAnimated,
|
|
92
|
+
title: options.title,
|
|
93
|
+
headerTitle: options.headerTitle,
|
|
94
|
+
titlePosition: options.titlePosition,
|
|
95
|
+
goBack: options.hiddenBack ? nil : { navigator.onBackSafe() },
|
|
96
|
+
scrollable: options.scrollable,
|
|
97
|
+
scrollToTopCallback: options.scrollToTopCallback,
|
|
98
|
+
useAvoidKeyboard: options.useAvoidKeyboard,
|
|
99
|
+
keyboardShouldPersistTaps: options.keyboardShouldPersistTaps,
|
|
100
|
+
footer: options.footer,
|
|
101
|
+
headerRight: options.resolvedHeaderRight,
|
|
102
|
+
animatedHeader: options.animatedHeader,
|
|
103
|
+
layoutOffset: options.layoutOffset,
|
|
104
|
+
inputSearchProps: options.inputSearchProps,
|
|
105
|
+
fabProps: options.fabProps,
|
|
106
|
+
content: { screen.content() }
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// MARK: - Overplay host
|
|
112
|
+
|
|
113
|
+
@available(iOS 16.0, *)
|
|
114
|
+
private struct OverplayHost: View {
|
|
115
|
+
let item: OverplayItem
|
|
116
|
+
@EnvironmentObject var navigator: Navigator
|
|
117
|
+
|
|
118
|
+
var body: some View {
|
|
119
|
+
// Each component self-animates on appear and drives its own exit through
|
|
120
|
+
// the Navigator before the item is removed (mirrors Compose's overplay).
|
|
121
|
+
switch item.type {
|
|
122
|
+
case .modal:
|
|
123
|
+
ModalScreen(barrierDismissible: item.barrierDismissible) {
|
|
124
|
+
item.content()
|
|
125
|
+
}
|
|
126
|
+
.id(item.id)
|
|
127
|
+
case .bottomSheet:
|
|
128
|
+
BottomSheetView(
|
|
129
|
+
header: item.header ?? .title(),
|
|
130
|
+
isSurface: item.isSurface,
|
|
131
|
+
barrierDismissible: item.barrierDismissible
|
|
132
|
+
) {
|
|
133
|
+
item.content()
|
|
134
|
+
}
|
|
135
|
+
.id(item.id)
|
|
136
|
+
case .snackBar:
|
|
137
|
+
if let snackBar = item.snackBar {
|
|
138
|
+
SnackBarView(snackBar: snackBar, bottomInset: safeAreaBottomInset() + Spacing.S)
|
|
139
|
+
.id(item.id)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/// Bottom safe-area inset (home indicator), used to lift the snack bar.
|
|
146
|
+
@available(iOS 16.0, *)
|
|
147
|
+
private func safeAreaBottomInset() -> CGFloat {
|
|
148
|
+
UIApplication.shared.connectedScenes
|
|
149
|
+
.compactMap { ($0 as? UIWindowScene)?.keyWindow?.safeAreaInsets.bottom }
|
|
150
|
+
.first ?? 0
|
|
151
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
//
|
|
2
|
+
// NavigationOptions.swift
|
|
3
|
+
// MoMoUIKits
|
|
4
|
+
//
|
|
5
|
+
// SwiftUI mirror of Compose's NavigationOptions.
|
|
6
|
+
// Each option lines up with a parameter on the existing `Screen` view,
|
|
7
|
+
// so NavigationContainer can auto-wrap a registered screen body in `Screen(options)`.
|
|
8
|
+
//
|
|
9
|
+
|
|
10
|
+
import SwiftUI
|
|
11
|
+
|
|
12
|
+
public struct NavigationOptions {
|
|
13
|
+
public var screenName: String?
|
|
14
|
+
public var title: String
|
|
15
|
+
/// Rich header title (mirrors Compose's `headerTitle`). When set to `.user`
|
|
16
|
+
/// the header renders an avatar group instead of `title`; `.default` keeps
|
|
17
|
+
/// the plain `title` text.
|
|
18
|
+
public var headerTitle: HeaderTitle?
|
|
19
|
+
public var titlePosition: TitlePosition
|
|
20
|
+
public var headerType: HeaderType
|
|
21
|
+
/// Mirrors Compose's `HeaderType.Extended/Default(useAnimated = ...)`: when true
|
|
22
|
+
/// and `inputSearchProps` is set, the search bar animates into the header on scroll.
|
|
23
|
+
public var useAnimated: Bool
|
|
24
|
+
public var headerTransparent: Bool
|
|
25
|
+
public var fullScreenContent: Bool
|
|
26
|
+
public var hiddenBack: Bool
|
|
27
|
+
public var backgroundColor: Color?
|
|
28
|
+
public var tintColor: Color?
|
|
29
|
+
public var scrollable: Bool
|
|
30
|
+
/// Mirrors Compose's `ScrollData.scrollToTopCallback`: invoked when the
|
|
31
|
+
/// screen is asked to scroll to top (e.g. on a status-bar tap).
|
|
32
|
+
public var scrollToTopCallback: (() -> Void)?
|
|
33
|
+
public var useAvoidKeyboard: Bool
|
|
34
|
+
/// Mirrors Compose's `KeyboardOptions.keyboardShouldPersistTaps`: when true,
|
|
35
|
+
/// tapping anywhere on the screen dismisses the keyboard.
|
|
36
|
+
public var keyboardShouldPersistTaps: Bool
|
|
37
|
+
/// Mirrors Compose's `HeaderBackProps`: drives the prevent-back confirm popup.
|
|
38
|
+
public var headerBackProps: HeaderBackProps?
|
|
39
|
+
/// Typed toolkit data for the default header right control (mirrors
|
|
40
|
+
/// Compose's `HeaderRight.Toolkit`). Use `headerRight` for `.custom` and nil
|
|
41
|
+
/// for `.none`.
|
|
42
|
+
public var headerRightData: HeaderRightData?
|
|
43
|
+
public var headerRight: (() -> any View)?
|
|
44
|
+
public var footer: (() -> AnyView)?
|
|
45
|
+
public var animatedHeader: AnimatedHeader?
|
|
46
|
+
public var layoutOffset: CGFloat
|
|
47
|
+
public var inputSearchProps: InputSearchProps?
|
|
48
|
+
public var fabProps: FabProps?
|
|
49
|
+
public var onBackHandler: (() -> Void)?
|
|
50
|
+
|
|
51
|
+
public init(
|
|
52
|
+
screenName: String? = nil,
|
|
53
|
+
title: String = "Stack",
|
|
54
|
+
headerTitle: HeaderTitle? = nil,
|
|
55
|
+
titlePosition: TitlePosition = .left,
|
|
56
|
+
headerType: HeaderType = .default,
|
|
57
|
+
useAnimated: Bool = false,
|
|
58
|
+
headerTransparent: Bool = false,
|
|
59
|
+
fullScreenContent: Bool = false,
|
|
60
|
+
hiddenBack: Bool = false,
|
|
61
|
+
backgroundColor: Color? = nil,
|
|
62
|
+
tintColor: Color? = Colors.black17,
|
|
63
|
+
scrollable: Bool = true,
|
|
64
|
+
scrollToTopCallback: (() -> Void)? = nil,
|
|
65
|
+
useAvoidKeyboard: Bool = true,
|
|
66
|
+
keyboardShouldPersistTaps: Bool = false,
|
|
67
|
+
headerBackProps: HeaderBackProps? = nil,
|
|
68
|
+
headerRightData: HeaderRightData? = nil,
|
|
69
|
+
headerRight: (() -> any View)? = { HeaderRight() },
|
|
70
|
+
footer: (() -> AnyView)? = nil,
|
|
71
|
+
animatedHeader: AnimatedHeader? = nil,
|
|
72
|
+
layoutOffset: CGFloat = 56,
|
|
73
|
+
inputSearchProps: InputSearchProps? = nil,
|
|
74
|
+
fabProps: FabProps? = nil,
|
|
75
|
+
onBackHandler: (() -> Void)? = nil
|
|
76
|
+
) {
|
|
77
|
+
self.screenName = screenName
|
|
78
|
+
self.title = title
|
|
79
|
+
self.headerTitle = headerTitle
|
|
80
|
+
self.titlePosition = titlePosition
|
|
81
|
+
self.headerType = headerType
|
|
82
|
+
self.useAnimated = useAnimated
|
|
83
|
+
self.headerTransparent = headerTransparent
|
|
84
|
+
self.fullScreenContent = fullScreenContent
|
|
85
|
+
self.hiddenBack = hiddenBack
|
|
86
|
+
self.backgroundColor = backgroundColor
|
|
87
|
+
self.tintColor = tintColor
|
|
88
|
+
self.scrollable = scrollable
|
|
89
|
+
self.scrollToTopCallback = scrollToTopCallback
|
|
90
|
+
self.useAvoidKeyboard = useAvoidKeyboard
|
|
91
|
+
self.keyboardShouldPersistTaps = keyboardShouldPersistTaps
|
|
92
|
+
self.headerBackProps = headerBackProps
|
|
93
|
+
self.headerRightData = headerRightData
|
|
94
|
+
self.headerRight = headerRight
|
|
95
|
+
self.footer = footer
|
|
96
|
+
self.animatedHeader = animatedHeader
|
|
97
|
+
self.layoutOffset = layoutOffset
|
|
98
|
+
self.inputSearchProps = inputSearchProps
|
|
99
|
+
self.fabProps = fabProps
|
|
100
|
+
self.onBackHandler = onBackHandler
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
extension NavigationOptions {
|
|
105
|
+
var resolvedHeaderRight: (() -> any View)? {
|
|
106
|
+
guard let headerRightData else { return headerRight }
|
|
107
|
+
return { HeaderRight(headerRight: headerRightData, tintColor: tintColor) }
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Navigator.swift
|
|
3
|
+
// MoMoUIKits
|
|
4
|
+
//
|
|
5
|
+
// SwiftUI mirror of Compose's Navigator + DynamicScreenRegistry.
|
|
6
|
+
// Screens are registered by Int id; the NavigationStack path stores routes
|
|
7
|
+
// by id and looks up content from the registry on render.
|
|
8
|
+
//
|
|
9
|
+
|
|
10
|
+
import SwiftUI
|
|
11
|
+
import Combine
|
|
12
|
+
|
|
13
|
+
// MARK: - Routes
|
|
14
|
+
|
|
15
|
+
public struct DynamicScreenRoute: Hashable, Identifiable {
|
|
16
|
+
public let id: Int
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public struct DynamicDialogRoute: Hashable, Identifiable {
|
|
20
|
+
public let id: Int
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// MARK: - Registry
|
|
24
|
+
|
|
25
|
+
public struct DynamicScreen {
|
|
26
|
+
public let id: Int
|
|
27
|
+
public let name: String
|
|
28
|
+
public let content: () -> AnyView
|
|
29
|
+
public var options: NavigationOptions?
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public final class DynamicScreenRegistry {
|
|
33
|
+
public static let shared = DynamicScreenRegistry()
|
|
34
|
+
|
|
35
|
+
private var screens: [Int: DynamicScreen] = [:]
|
|
36
|
+
private var idCounter: Int = 1
|
|
37
|
+
|
|
38
|
+
private init() {}
|
|
39
|
+
|
|
40
|
+
@discardableResult
|
|
41
|
+
public func register(
|
|
42
|
+
screenName: String = "",
|
|
43
|
+
content: @escaping () -> AnyView,
|
|
44
|
+
options: NavigationOptions? = nil
|
|
45
|
+
) -> DynamicScreenRoute {
|
|
46
|
+
let id = idCounter
|
|
47
|
+
idCounter += 1
|
|
48
|
+
screens[id] = DynamicScreen(id: id, name: screenName, content: content, options: options)
|
|
49
|
+
return DynamicScreenRoute(id: id)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public func unregister(id: Int) {
|
|
53
|
+
screens.removeValue(forKey: id)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public func unregisterAll() {
|
|
57
|
+
screens.removeAll()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public func getScreen(id: Int) -> DynamicScreen? { screens[id] }
|
|
61
|
+
|
|
62
|
+
public func latest() -> DynamicScreen? {
|
|
63
|
+
screens.max(by: { $0.key < $1.key })?.value
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
public func setOptions(id: Int, options: NavigationOptions) {
|
|
67
|
+
screens[id]?.options = options
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// MARK: - Overplay
|
|
72
|
+
|
|
73
|
+
public enum OverplayType {
|
|
74
|
+
case modal, bottomSheet, snackBar
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public struct OverplayItem: Identifiable {
|
|
78
|
+
public let id = UUID()
|
|
79
|
+
public let type: OverplayType
|
|
80
|
+
public let content: () -> AnyView
|
|
81
|
+
public let barrierDismissible: Bool
|
|
82
|
+
public let onDismiss: (() -> Void)?
|
|
83
|
+
// Bottom-sheet params (mirrors Compose's OverplayComponentParams.BottomSheet).
|
|
84
|
+
public var isSurface: Bool = false
|
|
85
|
+
public var header: BottomSheetHeader? = nil
|
|
86
|
+
// Snack-bar payload (mirrors Compose's SnackBar value).
|
|
87
|
+
public var snackBar: SnackBar? = nil
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// MARK: - Navigator
|
|
91
|
+
|
|
92
|
+
@available(iOS 16.0, *)
|
|
93
|
+
public final class Navigator: ObservableObject {
|
|
94
|
+
@Published public var path: [DynamicScreenRoute] = []
|
|
95
|
+
@Published public var presented: DynamicDialogRoute?
|
|
96
|
+
@Published public var overplay: OverplayItem?
|
|
97
|
+
|
|
98
|
+
/// Animated-close handler registered by the active overplay component
|
|
99
|
+
/// (mirrors Compose's `OverplayComponentRegistry.bindClose`). When set, a
|
|
100
|
+
/// dismiss request runs the component's exit animation before the item is
|
|
101
|
+
/// actually removed via `finishOverplayDismiss`.
|
|
102
|
+
private var overplayDismissHandler: (() -> Void)?
|
|
103
|
+
|
|
104
|
+
public private(set) var rootRoute: DynamicScreenRoute
|
|
105
|
+
|
|
106
|
+
public init(
|
|
107
|
+
initialScreenName: String = "",
|
|
108
|
+
initialContent: @escaping () -> AnyView,
|
|
109
|
+
options: NavigationOptions? = nil
|
|
110
|
+
) {
|
|
111
|
+
self.rootRoute = DynamicScreenRegistry.shared.register(
|
|
112
|
+
screenName: initialScreenName,
|
|
113
|
+
content: initialContent,
|
|
114
|
+
options: options
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// MARK: Stack
|
|
119
|
+
|
|
120
|
+
public func push<V: View>(@ViewBuilder _ content: @escaping () -> V, options: NavigationOptions? = nil) {
|
|
121
|
+
let route = DynamicScreenRegistry.shared.register(
|
|
122
|
+
screenName: options?.screenName ?? "",
|
|
123
|
+
content: { AnyView(content()) },
|
|
124
|
+
options: options
|
|
125
|
+
)
|
|
126
|
+
path.append(route)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
public func push<V: View>(
|
|
130
|
+
screenName: String,
|
|
131
|
+
@ViewBuilder _ content: @escaping () -> V,
|
|
132
|
+
options: NavigationOptions? = nil
|
|
133
|
+
) {
|
|
134
|
+
let route = DynamicScreenRegistry.shared.register(
|
|
135
|
+
screenName: screenName,
|
|
136
|
+
content: { AnyView(content()) },
|
|
137
|
+
options: options
|
|
138
|
+
)
|
|
139
|
+
path.append(route)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
public func replace<V: View>(@ViewBuilder _ content: @escaping () -> V, options: NavigationOptions? = nil) {
|
|
143
|
+
guard !path.isEmpty else { return }
|
|
144
|
+
let removed = path.removeLast()
|
|
145
|
+
DynamicScreenRegistry.shared.unregister(id: removed.id)
|
|
146
|
+
push(content, options: options)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
public func replace<V: View>(
|
|
150
|
+
screenName: String,
|
|
151
|
+
@ViewBuilder _ content: @escaping () -> V,
|
|
152
|
+
options: NavigationOptions? = nil
|
|
153
|
+
) {
|
|
154
|
+
guard !path.isEmpty else { return }
|
|
155
|
+
let removed = path.removeLast()
|
|
156
|
+
DynamicScreenRegistry.shared.unregister(id: removed.id)
|
|
157
|
+
push(screenName: screenName, content, options: options)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
public func reset<V: View>(@ViewBuilder _ content: @escaping () -> V, options: NavigationOptions? = nil) {
|
|
161
|
+
for route in path { DynamicScreenRegistry.shared.unregister(id: route.id) }
|
|
162
|
+
DynamicScreenRegistry.shared.unregister(id: rootRoute.id)
|
|
163
|
+
path.removeAll()
|
|
164
|
+
let route = DynamicScreenRegistry.shared.register(
|
|
165
|
+
screenName: options?.screenName ?? "",
|
|
166
|
+
content: { AnyView(content()) },
|
|
167
|
+
options: options
|
|
168
|
+
)
|
|
169
|
+
rootRoute = route
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
public func reset<V: View>(
|
|
173
|
+
screenName: String,
|
|
174
|
+
@ViewBuilder _ content: @escaping () -> V,
|
|
175
|
+
options: NavigationOptions? = nil
|
|
176
|
+
) {
|
|
177
|
+
for route in path { DynamicScreenRegistry.shared.unregister(id: route.id) }
|
|
178
|
+
DynamicScreenRegistry.shared.unregister(id: rootRoute.id)
|
|
179
|
+
path.removeAll()
|
|
180
|
+
let route = DynamicScreenRegistry.shared.register(
|
|
181
|
+
screenName: screenName,
|
|
182
|
+
content: { AnyView(content()) },
|
|
183
|
+
options: options
|
|
184
|
+
)
|
|
185
|
+
rootRoute = route
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
public func pop(_ count: Int = 1, callback: (() -> Void)? = nil) {
|
|
189
|
+
var remaining = count
|
|
190
|
+
while remaining > 0 {
|
|
191
|
+
if overplay != nil {
|
|
192
|
+
hideOverplay()
|
|
193
|
+
} else if presented != nil {
|
|
194
|
+
let dismissedId = presented?.id
|
|
195
|
+
presented = nil
|
|
196
|
+
if let id = dismissedId { DynamicScreenRegistry.shared.unregister(id: id) }
|
|
197
|
+
} else if !path.isEmpty {
|
|
198
|
+
let removed = path.removeLast()
|
|
199
|
+
DynamicScreenRegistry.shared.unregister(id: removed.id)
|
|
200
|
+
} else {
|
|
201
|
+
break
|
|
202
|
+
}
|
|
203
|
+
remaining -= 1
|
|
204
|
+
}
|
|
205
|
+
callback?()
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
public func popToRoot() {
|
|
209
|
+
for route in path { DynamicScreenRegistry.shared.unregister(id: route.id) }
|
|
210
|
+
path.removeAll()
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
public func onBackSafe(callback: (() -> Void)? = nil) {
|
|
214
|
+
let latest = DynamicScreenRegistry.shared.latest()
|
|
215
|
+
if let onBack = latest?.options?.onBackHandler {
|
|
216
|
+
onBack()
|
|
217
|
+
return
|
|
218
|
+
}
|
|
219
|
+
if let preventBack = latest?.options?.headerBackProps?.preventBack {
|
|
220
|
+
showModal {
|
|
221
|
+
PopupDisplay(
|
|
222
|
+
isPresented: .constant(true),
|
|
223
|
+
title: preventBack.title,
|
|
224
|
+
description: preventBack.description,
|
|
225
|
+
url: preventBack.image,
|
|
226
|
+
buttonDirection: preventBack.buttonDirection,
|
|
227
|
+
buttonType: .button,
|
|
228
|
+
actionButtonTitle: preventBack.primary?.title ?? "",
|
|
229
|
+
closeButtonTitle: preventBack.secondary?.title ?? "",
|
|
230
|
+
onPressAction: { [weak self] in
|
|
231
|
+
preventBack.primary?.onPress?()
|
|
232
|
+
// Close the popup, then leave the screen (matches Compose's pop(2)).
|
|
233
|
+
self?.pop(2, callback: callback)
|
|
234
|
+
},
|
|
235
|
+
onPressCloseButton: { [weak self] in
|
|
236
|
+
preventBack.secondary?.onPress?()
|
|
237
|
+
self?.hideOverplay()
|
|
238
|
+
},
|
|
239
|
+
onClose: { [weak self] in
|
|
240
|
+
preventBack.onIconClose?()
|
|
241
|
+
self?.hideOverplay()
|
|
242
|
+
},
|
|
243
|
+
errorCode: preventBack.error,
|
|
244
|
+
isShowCloseIcon: preventBack.isShowCloseIcon
|
|
245
|
+
)
|
|
246
|
+
}
|
|
247
|
+
return
|
|
248
|
+
}
|
|
249
|
+
pop(1, callback: callback)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// MARK: Modal-style screen (vertical slide)
|
|
253
|
+
|
|
254
|
+
public func present<V: View>(@ViewBuilder _ content: @escaping () -> V, options: NavigationOptions? = nil) {
|
|
255
|
+
let route = DynamicScreenRegistry.shared.register(
|
|
256
|
+
screenName: options?.screenName ?? "",
|
|
257
|
+
content: { AnyView(content()) },
|
|
258
|
+
options: options
|
|
259
|
+
)
|
|
260
|
+
presented = DynamicDialogRoute(id: route.id)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
public func present<V: View>(
|
|
264
|
+
screenName: String,
|
|
265
|
+
@ViewBuilder _ content: @escaping () -> V,
|
|
266
|
+
options: NavigationOptions? = nil
|
|
267
|
+
) {
|
|
268
|
+
let route = DynamicScreenRegistry.shared.register(
|
|
269
|
+
screenName: screenName,
|
|
270
|
+
content: { AnyView(content()) },
|
|
271
|
+
options: options
|
|
272
|
+
)
|
|
273
|
+
presented = DynamicDialogRoute(id: route.id)
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
public func dismiss() {
|
|
277
|
+
if let id = presented?.id {
|
|
278
|
+
DynamicScreenRegistry.shared.unregister(id: id)
|
|
279
|
+
}
|
|
280
|
+
presented = nil
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// MARK: Overplay
|
|
284
|
+
|
|
285
|
+
public func showModal<V: View>(
|
|
286
|
+
@ViewBuilder _ content: @escaping () -> V,
|
|
287
|
+
barrierDismissible: Bool = true,
|
|
288
|
+
onDismiss: (() -> Void)? = nil
|
|
289
|
+
) {
|
|
290
|
+
overplayDismissHandler = nil
|
|
291
|
+
overplay = OverplayItem(
|
|
292
|
+
type: .modal,
|
|
293
|
+
content: { AnyView(content()) },
|
|
294
|
+
barrierDismissible: barrierDismissible,
|
|
295
|
+
onDismiss: onDismiss
|
|
296
|
+
)
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
public func showBottomSheet<V: View>(
|
|
300
|
+
@ViewBuilder _ content: @escaping () -> V,
|
|
301
|
+
isSurface: Bool = false,
|
|
302
|
+
barrierDismissible: Bool = true,
|
|
303
|
+
header: BottomSheetHeader? = nil,
|
|
304
|
+
onDismiss: (() -> Void)? = nil
|
|
305
|
+
) {
|
|
306
|
+
overplayDismissHandler = nil
|
|
307
|
+
overplay = OverplayItem(
|
|
308
|
+
type: .bottomSheet,
|
|
309
|
+
content: { AnyView(content()) },
|
|
310
|
+
barrierDismissible: barrierDismissible,
|
|
311
|
+
onDismiss: onDismiss,
|
|
312
|
+
isSurface: isSurface,
|
|
313
|
+
header: header
|
|
314
|
+
)
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/// Mirrors Compose's `showSnackBar(snackBar:)`.
|
|
318
|
+
public func showSnackBar(_ snackBar: SnackBar, onDismiss: (() -> Void)? = nil) {
|
|
319
|
+
overplayDismissHandler = nil
|
|
320
|
+
overplay = OverplayItem(
|
|
321
|
+
type: .snackBar,
|
|
322
|
+
content: { AnyView(EmptyView()) },
|
|
323
|
+
barrierDismissible: false,
|
|
324
|
+
onDismiss: onDismiss,
|
|
325
|
+
snackBar: snackBar
|
|
326
|
+
)
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// MARK: Overplay dismissal
|
|
330
|
+
|
|
331
|
+
/// Registered by the active overplay component so external dismiss requests
|
|
332
|
+
/// run its exit animation (mirrors Compose's `bindClose`).
|
|
333
|
+
public func registerOverplayDismiss(_ handler: @escaping () -> Void) {
|
|
334
|
+
overplayDismissHandler = handler
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/// Removes the overplay and fires its `onDismiss` (mirrors Compose's
|
|
338
|
+
/// `hardClearAfterDismiss`). Called by a component once its exit animation
|
|
339
|
+
/// has completed.
|
|
340
|
+
public func finishOverplayDismiss() {
|
|
341
|
+
let dismissCallback = overplay?.onDismiss
|
|
342
|
+
overplayDismissHandler = nil
|
|
343
|
+
overplay = nil
|
|
344
|
+
dismissCallback?()
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
public func hideOverplay() {
|
|
348
|
+
if let close = overplayDismissHandler {
|
|
349
|
+
// Component runs its exit animation, then calls finishOverplayDismiss.
|
|
350
|
+
overplayDismissHandler = nil
|
|
351
|
+
close()
|
|
352
|
+
} else {
|
|
353
|
+
finishOverplayDismiss()
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
public func hideSnackBar() {
|
|
358
|
+
if overplay?.type == .snackBar { hideOverplay() }
|
|
359
|
+
}
|
|
360
|
+
}
|