@momo-kits/native-kits 0.300.3 → 0.300.4-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.md +51 -7
- package/README.md +2 -2
- package/build.gradle.kts +13 -0
- package/compose/build.gradle.kts +197 -0
- package/compose/build.gradle.kts.backup +197 -0
- package/compose/compose.podspec +47 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/const/HostFont.android.kt +20 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +6 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/BackGesture.android.kt +12 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +7 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +153 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/ReservedRegions.android.kt +6 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +110 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/DesignSystemKits.kt +62 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +1071 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +269 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +65 -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 +81 -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 +338 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +175 -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 +115 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +89 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +128 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +209 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +542 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +49 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +86 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +125 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +231 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +189 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +478 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +114 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +265 -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 +223 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +265 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +185 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +343 -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 +84 -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 +361 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +108 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +308 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +59 -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 +21 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +90 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +330 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +220 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +473 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +122 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +207 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +92 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +560 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +86 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +125 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +207 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +501 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +176 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +182 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +193 -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 +236 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +180 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +325 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/HostFont.kt +17 -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 +194 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +287 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +54 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +50 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/ScreenLayout.kt +306 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +41 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +52 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +66 -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 +104 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +48 -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 +338 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/HostBackGestureBridge.kt +58 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +137 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +116 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +215 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +404 -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 +732 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackTransition.kt +148 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/SwipeBackHaptic.kt +40 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +233 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +217 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +86 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoBarCompression.kt +97 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoTabBar.kt +377 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +169 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +455 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +103 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderJourney.kt +106 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderLocation.kt +74 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +413 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +39 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +363 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HelpCenterRequest.kt +37 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SideBar.kt +192 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +133 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/ToolkitRequests.kt +41 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +135 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/BackGesture.kt +12 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +91 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +9 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +74 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ReservedRegions.kt +20 -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 +55 -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 +118 -0
- package/compose/src/commonTest/kotlin/vn/momo/kits/navigation/component/HelpCenterRequestTest.kt +44 -0
- package/compose/src/commonTest/kotlin/vn/momo/kits/navigation/component/ToolkitRequestsTest.kt +62 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/const/HostFont.ios.kt +42 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/HostBackGesture.ios.kt +45 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +36 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/BackGesture.ios.kt +38 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +66 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +217 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/ReservedRegions.ios.kt +138 -0
- package/gradle/libs.versions.toml +68 -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/ApplicationEnvironment.swift +24 -6
- package/ios/Application/DesignSystemKits.swift +100 -0
- package/ios/Application/DesignSystemKitsPayload.swift +68 -0
- package/ios/Application/MaxApi.swift +30 -3
- package/ios/Avatar/Avatar.swift +4 -3
- package/ios/Badge/Badge.swift +6 -4
- package/ios/Badge/BadgeDot.swift +1 -1
- package/ios/Badge/BadgeRibbon.swift +8 -2
- package/ios/Button/Button.swift +15 -12
- package/ios/CalculatorKeyboard/CalculatorKeyboard.swift +64 -18
- package/ios/Carousel/Carousel.swift +29 -12
- package/ios/Checkbox/Checkbox.swift +7 -3
- package/ios/Chip/Chip.swift +5 -4
- package/ios/Collapse/Collapse.swift +70 -19
- package/ios/Colors+Radius+Spacing/Colors.swift +10 -1
- package/ios/Colors+Radius+Spacing/Radius.swift +6 -0
- package/ios/DateTimePicker/DateTimePicker.swift +54 -20
- package/ios/DateTimePicker/WheelPicker.swift +103 -105
- package/ios/Divider/Divider.swift +37 -4
- package/ios/Extensions/Color++.swift +38 -9
- package/ios/Extensions/OptionalEnvironmentObject.swift +12 -0
- package/ios/Extensions/SkeletonUICompat.swift +11 -0
- package/ios/Icon/Icon.swift +21 -23
- package/ios/Icon/Icons.swift +1329 -0
- package/ios/IconButton/IconButton.swift +15 -7
- package/ios/Image/Image.swift +7 -23
- package/ios/Information/Information.swift +27 -9
- package/ios/Input/ErrorView.swift +2 -2
- package/ios/Input/Input.swift +171 -148
- package/ios/Input/InputPhoneNumber.swift +10 -9
- package/ios/Input/InputSearch.swift +107 -78
- package/ios/Input/InputTextArea.swift +133 -148
- package/ios/InputDropDown/InputDropDown.swift +10 -7
- package/ios/InputMoney/InputMoney.swift +32 -11
- package/ios/InputOTP/InputOTP.swift +22 -12
- package/ios/Layout/Card.swift +50 -0
- package/ios/Layout/GridContext.swift +187 -3
- package/ios/Layout/Item.swift +5 -4
- package/ios/Layout/ScreenLayout.swift +415 -0
- package/ios/Layout/Section.swift +4 -100
- package/ios/Loader/Loader.swift +5 -9
- package/ios/Lottie/LottieView.swift +14 -2
- package/ios/{Application/Navigation/Overplay → Navigation}/BottomSheet.swift +169 -29
- package/ios/Navigation/BottomTab/BottomTab.swift +332 -0
- package/ios/{Application/Navigation → Navigation}/BottomTab/BottomTabBar.swift +18 -7
- package/ios/Navigation/BottomTab/DuoBarCompression.swift +104 -0
- package/ios/Navigation/BottomTab/DuoTabBar.swift +329 -0
- package/ios/{Application → Navigation/Component}/FloatingButton.swift +43 -54
- package/ios/Navigation/Component/Header.swift +545 -0
- package/ios/Navigation/Component/HeaderBackground.swift +154 -0
- package/ios/Navigation/Component/HeaderJourney.swift +73 -0
- package/ios/Navigation/Component/HeaderLocation.swift +48 -0
- package/ios/Navigation/Component/HeaderRight.swift +425 -0
- package/ios/Navigation/Component/HeaderTitle.swift +36 -0
- package/ios/{Application/Navigation → Navigation/Component}/HeaderUser.swift +21 -24
- package/ios/Navigation/Component/SideBar.swift +183 -0
- package/ios/{Application/Navigation/Overplay → Navigation/Component}/SnackBar.swift +8 -8
- package/ios/Navigation/HostBackGestureBridge.swift +78 -0
- package/ios/{Application/Navigation/Overplay → Navigation}/ModalScreen.swift +9 -2
- package/ios/Navigation/Navigation.swift +204 -0
- package/ios/Navigation/NavigationContainer.swift +195 -0
- package/ios/{Application/Navigation → Navigation}/Navigator.swift +207 -107
- package/ios/Navigation/StackScreen.swift +930 -0
- package/ios/Navigation/StackTransition.swift +400 -0
- package/ios/Navigation/SwipeBackHaptic.swift +33 -0
- package/ios/{Application/Navigation → Navigation}/Tracking/ScreenTracker.swift +12 -5
- package/ios/OTPKeyboard/OTPKeyboard.swift +8 -11
- package/ios/Pagination/PaginationScroll.swift +2 -2
- package/ios/Popup/PopupDisplay.swift +72 -135
- package/ios/Popup/PopupInput.swift +10 -13
- package/ios/Popup/PopupLayout.swift +138 -0
- package/ios/Popup/PopupNotify.swift +59 -69
- package/ios/Popup/PopupPromotion.swift +31 -47
- package/ios/PopupView/FullscreenPopup.swift +13 -19
- package/ios/PopupView/PopupView.swift +1 -1
- package/ios/PopupView/Utils++.swift +0 -8
- package/ios/ProgressInfo/ProgressInfo.swift +4 -2
- package/ios/Radio/Radio.swift +2 -1
- package/ios/Rating/Rating.swift +9 -1
- package/ios/Resources/dot_loading.json +558 -0
- package/ios/Resources/lottie_circle_loader.json +1 -0
- package/ios/ScrollIndicator/ScrollIndicator.swift +11 -10
- package/ios/Skeleton/Skeleton.swift +22 -27
- package/ios/Slider/Slider.swift +16 -18
- package/ios/Stepper/Stepper.swift +7 -3
- package/ios/Steps/Steps.swift +8 -6
- package/ios/SuggestAction/SuggestAction.swift +5 -0
- package/ios/Swipeable/SwipeCell.swift +10 -6
- package/ios/Switch/Switch.swift +22 -20
- package/ios/TabView/TabView.swift +102 -21
- package/ios/Tag/Tag.swift +15 -4
- package/ios/Template/Logo/Logo.swift +2 -1
- package/ios/Template/TrustBanner/TrustBanner.swift +109 -55
- package/ios/Title/Title.swift +6 -17
- package/ios/Tooltip/Tooltip.swift +29 -14
- package/ios/Typography/FontScale.swift +17 -14
- package/ios/Typography/Text.swift +156 -20
- package/ios/Typography/Typography.swift +2 -2
- package/ios/Uploader/Uploader.swift +3 -1
- package/ios/native-kits.podspec +2 -3
- package/ios-demo/MoMoUIKitsDemo.podspec +1 -3
- package/ios-demo/README.md +120 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ContentView.swift +1 -1
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DuoTabDemo.swift +80 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +2 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IPhoneDuoDemo.swift +173 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/NavigationDemo.swift +77 -1
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupDisplayDemo.swift +1 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupNotifyDemo.swift +2 -2
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupPromotionDemo.swift +2 -0
- package/package.json +1 -1
- package/publish.sh +19 -2
- package/scripts/gen-ios-icons.mjs +36 -0
- package/settings.gradle.kts +64 -0
- package/ios/Application/Components.swift +0 -270
- package/ios/Application/ComposeApi.swift +0 -22
- package/ios/Application/HeaderRight.swift +0 -306
- package/ios/Application/Navigation/BottomTab/BottomTab.swift +0 -104
- package/ios/Application/Navigation/HeaderBackProps.swift +0 -66
- package/ios/Application/Navigation/HeaderTitle.swift +0 -57
- package/ios/Application/Navigation/NavigationContainer.swift +0 -213
- package/ios/Application/Navigation/NavigationOptions.swift +0 -109
- package/ios/Application/Navigation/NavigatorManager.swift +0 -22
- package/ios/Application/Navigation/component/Header.swift +0 -178
- package/ios/Application/Navigation/component/HeaderBackground.swift +0 -83
- package/ios/Application/Navigation/component/HeaderColor.swift +0 -65
- package/ios/Application/Navigation/component/HeaderRightWidthKey.swift +0 -11
- package/ios/Application/Navigation/component/NavigationFooter.swift +0 -90
- package/ios/Application/Navigation/component/NavigationHeaderRight.swift +0 -196
- package/ios/Application/Screen.swift +0 -250
- package/ios/Application/StackScreen.swift +0 -492
- package/ios/Typography/FontScaleStore.swift +0 -58
- package/ios/Typography/KitDesignSystem.swift +0 -17
- /package/ios/{Application/Navigation → Navigation}/BottomTab/CurvedContainer.swift +0 -0
|
@@ -44,8 +44,6 @@ private struct ShimmerLoading: View {
|
|
|
44
44
|
let durationMillis: Int
|
|
45
45
|
let angleOfAxisY: CGFloat
|
|
46
46
|
|
|
47
|
-
@State private var phase: CGFloat = 0
|
|
48
|
-
|
|
49
47
|
// Matches Compose `SHADOW_BRUSH_PERCENTAGE = 0.6f`.
|
|
50
48
|
private static let shadowBrushPercentage: CGFloat = 0.6
|
|
51
49
|
|
|
@@ -67,33 +65,30 @@ private struct ShimmerLoading: View {
|
|
|
67
65
|
size.width + widthOfShadowBrush
|
|
68
66
|
}
|
|
69
67
|
|
|
68
|
+
// Clock-driven rather than an onAppear animation: gradient points aren't reliably animatable,
|
|
69
|
+
// and a view first laid out at zero width (or resized later) would never (re)start.
|
|
70
70
|
var body: some View {
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
TimelineView(.animation) { timeline in
|
|
72
|
+
Rectangle().fill(gradient(at: timeline.date))
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private func gradient(at date: Date) -> LinearGradient {
|
|
77
|
+
let duration = Double(max(durationMillis, 1)) / 1000
|
|
78
|
+
let progress = date.timeIntervalSinceReferenceDate.truncatingRemainder(dividingBy: duration) / duration
|
|
79
|
+
let endX = CGFloat(progress) * animationTarget
|
|
80
|
+
let startX = endX - widthOfShadowBrush
|
|
73
81
|
|
|
74
|
-
|
|
75
|
-
.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
x: size.width > 0 ? endX / size.width : 0,
|
|
84
|
-
y: size.height > 0 ? angleOfAxisY / size.height : 0
|
|
85
|
-
)
|
|
86
|
-
)
|
|
82
|
+
return LinearGradient(
|
|
83
|
+
gradient: Gradient(colors: Self.shimmerColors),
|
|
84
|
+
startPoint: .init(
|
|
85
|
+
x: size.width > 0 ? startX / size.width : 0,
|
|
86
|
+
y: 0
|
|
87
|
+
),
|
|
88
|
+
endPoint: .init(
|
|
89
|
+
x: size.width > 0 ? endX / size.width : 0,
|
|
90
|
+
y: size.height > 0 ? angleOfAxisY / size.height : 0
|
|
87
91
|
)
|
|
88
|
-
|
|
89
|
-
guard size.width > 0 else { return }
|
|
90
|
-
phase = 0
|
|
91
|
-
withAnimation(
|
|
92
|
-
.linear(duration: Double(durationMillis) / 1000.0)
|
|
93
|
-
.repeatForever(autoreverses: false)
|
|
94
|
-
) {
|
|
95
|
-
phase = animationTarget
|
|
96
|
-
}
|
|
97
|
-
}
|
|
92
|
+
)
|
|
98
93
|
}
|
|
99
94
|
}
|
package/ios/Slider/Slider.swift
CHANGED
|
@@ -24,12 +24,14 @@ private func getValueForPosition(
|
|
|
24
24
|
step: CGFloat
|
|
25
25
|
) -> CGFloat {
|
|
26
26
|
let availableSpace = containerWidth - thumbWidth
|
|
27
|
-
if availableSpace <= 0 { return minV }
|
|
28
|
-
let relStepUnit = step / (maxV - minV)
|
|
27
|
+
if availableSpace <= 0 || maxV <= minV { return minV }
|
|
29
28
|
var relPosition = (positionInView - thumbWidth / 2) / availableSpace
|
|
29
|
+
// A zero step would make the snap math NaN, which later traps in `Int(_:)`.
|
|
30
|
+
if step <= 0 { return clampF(minV + relPosition * (maxV - minV), minV, maxV) }
|
|
31
|
+
let relStepUnit = step / (maxV - minV)
|
|
30
32
|
let relOffset = relPosition.truncatingRemainder(dividingBy: relStepUnit)
|
|
31
33
|
relPosition -= relOffset
|
|
32
|
-
if
|
|
34
|
+
if relOffset / relStepUnit >= 0.5 { relPosition += relStepUnit }
|
|
33
35
|
let steps = (relPosition / relStepUnit).rounded()
|
|
34
36
|
return clampF(minV + steps * step, minV, maxV)
|
|
35
37
|
}
|
|
@@ -49,7 +51,8 @@ private func formatLabel(_ value: CGFloat) -> String {
|
|
|
49
51
|
if value == value.rounded() {
|
|
50
52
|
return String(Int(value))
|
|
51
53
|
}
|
|
52
|
-
|
|
54
|
+
// Truncates to one decimal like Compose's `(value * 10).toLong() / 10.0`.
|
|
55
|
+
return String(Double((value * 10).rounded(.towardZero)) / 10)
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
// ── Component ─────────────────────────────────────────────────────────────────
|
|
@@ -64,8 +67,6 @@ public struct MomoSlider: View {
|
|
|
64
67
|
private let minV: CGFloat
|
|
65
68
|
private let maxV: CGFloat
|
|
66
69
|
private let step: CGFloat
|
|
67
|
-
private let initLow: CGFloat
|
|
68
|
-
private let initHigh: CGFloat
|
|
69
70
|
private let minRange: CGFloat
|
|
70
71
|
private let disableRange: Bool
|
|
71
72
|
private let floatingLabel: Bool
|
|
@@ -74,11 +75,10 @@ public struct MomoSlider: View {
|
|
|
74
75
|
private let onSliderTouchStart: (CGFloat, CGFloat) -> Void
|
|
75
76
|
private let onSliderTouchEnd: (CGFloat, CGFloat) -> Void
|
|
76
77
|
|
|
77
|
-
@State private var lowValue: CGFloat
|
|
78
|
-
@State private var highValue: CGFloat
|
|
78
|
+
@State private var lowValue: CGFloat
|
|
79
|
+
@State private var highValue: CGFloat
|
|
79
80
|
@State private var draggingLow: Bool = true
|
|
80
81
|
@State private var isDragging: Bool = false
|
|
81
|
-
@State private var didInit: Bool = false
|
|
82
82
|
|
|
83
83
|
public init(
|
|
84
84
|
min: CGFloat,
|
|
@@ -105,8 +105,10 @@ public struct MomoSlider: View {
|
|
|
105
105
|
self.onSliderTouchStart = onSliderTouchStart
|
|
106
106
|
self.onSliderTouchEnd = onSliderTouchEnd
|
|
107
107
|
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
let startLow = clampF(low ?? min, min, max)
|
|
109
|
+
let startHigh = disableRange ? max : clampF(high ?? max, min, max)
|
|
110
|
+
_lowValue = State(initialValue: startLow)
|
|
111
|
+
_highValue = State(initialValue: startHigh)
|
|
110
112
|
}
|
|
111
113
|
|
|
112
114
|
private var thumbColor: Color { disabled ? theme.colors.text.disable : theme.colors.primary }
|
|
@@ -165,17 +167,13 @@ public struct MomoSlider: View {
|
|
|
165
167
|
}
|
|
166
168
|
}
|
|
167
169
|
.frame(width: trackWidth, height: topPad + THUMB_SIZE, alignment: .topLeading)
|
|
170
|
+
// Compose's spring(stiffness = 1200) is critically damped.
|
|
171
|
+
.animation(.interpolatingSpring(stiffness: 1200, damping: 2 * sqrt(1200)), value: lowValue)
|
|
172
|
+
.animation(.interpolatingSpring(stiffness: 1200, damping: 2 * sqrt(1200)), value: highValue)
|
|
168
173
|
.contentShape(Rectangle())
|
|
169
174
|
.gesture(dragGesture(trackWidth: trackWidth))
|
|
170
175
|
}
|
|
171
176
|
.frame(height: (floatingLabel ? (THUMB_SIZE + LABEL_GAP) : 0) + THUMB_SIZE)
|
|
172
|
-
.onAppear {
|
|
173
|
-
if !didInit {
|
|
174
|
-
lowValue = initLow
|
|
175
|
-
highValue = initHigh
|
|
176
|
-
didInit = true
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
177
|
}
|
|
180
178
|
|
|
181
179
|
private var thumb: some View {
|
|
@@ -84,7 +84,6 @@ private struct StepperButton: View {
|
|
|
84
84
|
|
|
85
85
|
private struct StepperNumberView: View {
|
|
86
86
|
@Environment(\.appTheme) private var theme
|
|
87
|
-
@Environment(\.momoFontScale) private var fontScale
|
|
88
87
|
|
|
89
88
|
@Binding var text: String
|
|
90
89
|
var size: StepperSize
|
|
@@ -106,12 +105,13 @@ private struct StepperNumberView: View {
|
|
|
106
105
|
MomoText(text, typography: .descriptionDefaultRegular, color: textColor)
|
|
107
106
|
}
|
|
108
107
|
}
|
|
109
|
-
.
|
|
108
|
+
.kitFont(size: 12)
|
|
110
109
|
.ignoreBoldTextSetting()
|
|
111
110
|
.foregroundColor(textColor)
|
|
111
|
+
// Compose's min width includes the horizontal padding.
|
|
112
|
+
.padding(.horizontal, Spacing.XS)
|
|
112
113
|
.frame(minWidth: specs.numberMinWidth)
|
|
113
114
|
.frame(height: specs.numberHeight)
|
|
114
|
-
.padding(.horizontal, Spacing.XS)
|
|
115
115
|
.overlay(
|
|
116
116
|
RoundedRectangle(cornerRadius: Radius.S)
|
|
117
117
|
.stroke(borderColor, lineWidth: 1)
|
|
@@ -217,5 +217,9 @@ public struct MomoStepper: View {
|
|
|
217
217
|
if clamped != value { value = clamped }
|
|
218
218
|
editingText = String(clamped)
|
|
219
219
|
}
|
|
220
|
+
// Keeps the editable field in step with values set by the owner of the binding.
|
|
221
|
+
.onChange(of: value) { newValue in
|
|
222
|
+
editingText = String(newValue)
|
|
223
|
+
}
|
|
220
224
|
}
|
|
221
225
|
}
|
package/ios/Steps/Steps.swift
CHANGED
|
@@ -162,8 +162,9 @@ private struct StepsHorizontal: View {
|
|
|
162
162
|
|
|
163
163
|
var body: some View {
|
|
164
164
|
HStack(alignment: .top, spacing: 0) {
|
|
165
|
-
|
|
166
|
-
|
|
165
|
+
// Keyed by position like Compose: `StepItem.id` is a fresh UUID per instance.
|
|
166
|
+
ForEach(steps.indices, id: \.self) { index in
|
|
167
|
+
column(index: index, item: steps[index])
|
|
167
168
|
.frame(maxWidth: .infinity)
|
|
168
169
|
}
|
|
169
170
|
}
|
|
@@ -234,7 +235,7 @@ private struct StepsHorizontal: View {
|
|
|
234
235
|
.clipShape(RoundedCorner(radius: Radius.XS, corners: [.topLeft, .bottomLeft]))
|
|
235
236
|
}
|
|
236
237
|
}
|
|
237
|
-
.frame(maxWidth: .infinity)
|
|
238
|
+
.frame(maxWidth: .infinity, alignment: .leading)
|
|
238
239
|
|
|
239
240
|
if !item.title.isEmpty {
|
|
240
241
|
MomoText(item.title, typography: titleStyle, color: titleColor)
|
|
@@ -316,8 +317,8 @@ private struct StepsVertical: View {
|
|
|
316
317
|
|
|
317
318
|
var body: some View {
|
|
318
319
|
VStack(spacing: 0) {
|
|
319
|
-
ForEach(
|
|
320
|
-
row(index: index, item:
|
|
320
|
+
ForEach(steps.indices, id: \.self) { index in
|
|
321
|
+
row(index: index, item: steps[index])
|
|
321
322
|
}
|
|
322
323
|
}
|
|
323
324
|
.frame(maxWidth: .infinity)
|
|
@@ -358,8 +359,9 @@ private struct StepsVertical: View {
|
|
|
358
359
|
customIcon: customIcon
|
|
359
360
|
)
|
|
360
361
|
if !isLast {
|
|
362
|
+
// Compose pads inside the fixed height, so the drawn line is 8pt shorter.
|
|
361
363
|
lineColor
|
|
362
|
-
.frame(width: 2, height: connectorHeight)
|
|
364
|
+
.frame(width: 2, height: connectorHeight - Spacing.XS * 2)
|
|
363
365
|
.padding(.vertical, Spacing.XS)
|
|
364
366
|
}
|
|
365
367
|
}
|
|
@@ -65,6 +65,11 @@ public struct SuggestAction: View {
|
|
|
65
65
|
|
|
66
66
|
Text(annotatedMessage)
|
|
67
67
|
.foregroundColor(theme.colors.text.default)
|
|
68
|
+
.lineSpacing(
|
|
69
|
+
fontScale(TypographyStyle.bodyDefaultRegular.lineHeight)
|
|
70
|
+
- fontScale(TypographyStyle.bodyDefaultRegular.fontSize)
|
|
71
|
+
)
|
|
72
|
+
.ignoreBoldTextSetting()
|
|
68
73
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
69
74
|
.padding(.trailing, Spacing.M)
|
|
70
75
|
|
|
@@ -20,6 +20,7 @@ public struct Swipe<Content: View>: View {
|
|
|
20
20
|
|
|
21
21
|
@State private var offsetX: CGFloat = 0
|
|
22
22
|
@State private var dragStartOffsetX: CGFloat?
|
|
23
|
+
@GestureState private var isDragging = false
|
|
23
24
|
|
|
24
25
|
public init(
|
|
25
26
|
leftActions: [SwipeAction] = [],
|
|
@@ -87,14 +88,17 @@ public struct Swipe<Content: View>: View {
|
|
|
87
88
|
.offset(x: offsetX)
|
|
88
89
|
.gesture(
|
|
89
90
|
DragGesture(minimumDistance: 8, coordinateSpace: .local)
|
|
91
|
+
.updating($isDragging) { _, dragging, _ in dragging = true }
|
|
90
92
|
.onChanged { value in
|
|
91
93
|
dragOnChanged(value: value, leftWidth: leftWidth, rightWidth: rightWidth)
|
|
92
94
|
}
|
|
93
|
-
.onEnded { _ in
|
|
94
|
-
dragStartOffsetX = nil
|
|
95
|
-
snapToClosest(leftWidth: leftWidth, rightWidth: rightWidth)
|
|
96
|
-
}
|
|
97
95
|
)
|
|
96
|
+
// Gesture state also resets on cancel, so a stolen drag still snaps (Compose `onDragCancel`).
|
|
97
|
+
.onChange(of: isDragging) { dragging in
|
|
98
|
+
guard !dragging else { return }
|
|
99
|
+
dragStartOffsetX = nil
|
|
100
|
+
snapToClosest(leftWidth: leftWidth, rightWidth: rightWidth)
|
|
101
|
+
}
|
|
98
102
|
}
|
|
99
103
|
.frame(maxWidth: .infinity)
|
|
100
104
|
.frame(height: height)
|
|
@@ -166,7 +170,7 @@ private struct SwipeActionButton: View {
|
|
|
166
170
|
|
|
167
171
|
var body: some View {
|
|
168
172
|
SwiftUI.Button(action: action.onPress) {
|
|
169
|
-
VStack(spacing:
|
|
173
|
+
VStack(spacing: 0) {
|
|
170
174
|
if !action.icon.isEmpty {
|
|
171
175
|
Icon(source: action.icon, size: 20, color: Colors.black01)
|
|
172
176
|
}
|
|
@@ -184,7 +188,7 @@ private struct SwipeActionButton: View {
|
|
|
184
188
|
.background(action.backgroundColor ?? defaultBackgroundColor)
|
|
185
189
|
.clipShape(RoundedRectangle(cornerRadius: itemRadius))
|
|
186
190
|
}
|
|
187
|
-
.buttonStyle(
|
|
191
|
+
.buttonStyle(ActiveOpacityButtonStyle())
|
|
188
192
|
}
|
|
189
193
|
}
|
|
190
194
|
|
package/ios/Switch/Switch.swift
CHANGED
|
@@ -41,29 +41,31 @@ public struct Switch: View {
|
|
|
41
41
|
accessibilityId?.isEmpty == false ? accessibilityId! : "toggle_\(title?.isEmpty == false ? title! : "unknown")_\(value)"
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
private func toggle() {
|
|
45
|
+
// Not re-read from the binding: a `.constant` / one-way binding would report the stale value.
|
|
46
|
+
let newValue = !value
|
|
47
|
+
value = newValue
|
|
48
|
+
onChange?(newValue)
|
|
49
|
+
}
|
|
50
|
+
|
|
44
51
|
public var body: some View {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
.background(circleColor)
|
|
59
|
-
.clipShape(Circle())
|
|
60
|
-
.padding(.leading, Spacing.XS)
|
|
61
|
-
.padding(.trailing, Spacing.XS)
|
|
52
|
+
// The whole track is the label so all of it is tappable, as in Compose.
|
|
53
|
+
SwiftUI.Button(action: toggle) {
|
|
54
|
+
Circle()
|
|
55
|
+
.fill(backgroundColor)
|
|
56
|
+
.frame(width: 6, height: 6)
|
|
57
|
+
.frame(width: 14, height: 14)
|
|
58
|
+
.background(Circle().fill(circleColor))
|
|
59
|
+
.padding(.horizontal, Spacing.XS)
|
|
60
|
+
.frame(width: 38, height: 20, alignment: value ? .trailing : .leading)
|
|
61
|
+
.background(backgroundColor)
|
|
62
|
+
.clipShape(Capsule())
|
|
63
|
+
.contentShape(Capsule())
|
|
64
|
+
.animation(.default, value: value)
|
|
62
65
|
}
|
|
66
|
+
// Custom style so `.disabled` doesn't add a system dim on top of the disabled colors.
|
|
67
|
+
.buttonStyle(ActiveOpacityButtonStyle())
|
|
63
68
|
.disabled(disabled)
|
|
64
|
-
.frame(width: 38, height: 20, alignment: value ? .trailing : .leading)
|
|
65
|
-
.background(backgroundColor)
|
|
66
|
-
.clipShape(Capsule())
|
|
67
69
|
.accessibilityIdentifier(automationId)
|
|
68
70
|
}
|
|
69
71
|
}
|
|
@@ -328,8 +328,13 @@ private struct ScrollableTabBar: View {
|
|
|
328
328
|
Rectangle()
|
|
329
329
|
.stroke(theme.colors.border.default, lineWidth: 0.5)
|
|
330
330
|
)
|
|
331
|
+
// Compose scrolls the selected tab to the leading edge, initial page included.
|
|
331
332
|
.onChange(of: selectedIndex) { index in
|
|
332
|
-
withAnimation { proxy.scrollTo(index, anchor: .
|
|
333
|
+
withAnimation { proxy.scrollTo(index, anchor: .leading) }
|
|
334
|
+
}
|
|
335
|
+
.onAppear {
|
|
336
|
+
guard selectedIndex > 0 else { return }
|
|
337
|
+
DispatchQueue.main.async { proxy.scrollTo(selectedIndex, anchor: .leading) }
|
|
333
338
|
}
|
|
334
339
|
}
|
|
335
340
|
}
|
|
@@ -346,6 +351,11 @@ private struct TabFramePreferenceKey: PreferenceKey {
|
|
|
346
351
|
// Card tab bar
|
|
347
352
|
// ---------------------------------------------------------------------------
|
|
348
353
|
|
|
354
|
+
private let cardTabHeight: CGFloat = 40
|
|
355
|
+
private let cardTabActiveHeight: CGFloat = 44
|
|
356
|
+
|
|
357
|
+
/// Two layers, as in Compose / react-kits: a flat strip where every tab looks unselected,
|
|
358
|
+
/// and one raised card for the active tab, 4pt taller and joined to the strip by curved ears.
|
|
349
359
|
private struct CardTabBar: View {
|
|
350
360
|
@Environment(\.appTheme) private var theme
|
|
351
361
|
|
|
@@ -357,47 +367,116 @@ private struct CardTabBar: View {
|
|
|
357
367
|
let onPress: (Int) -> Void
|
|
358
368
|
|
|
359
369
|
var body: some View {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
370
|
+
GeometryReader { geo in
|
|
371
|
+
let itemWidth = geo.size.width / CGFloat(Swift.max(tabs.count, 1))
|
|
372
|
+
|
|
373
|
+
ZStack(alignment: .bottomLeading) {
|
|
374
|
+
HStack(spacing: 0) {
|
|
375
|
+
ForEach(tabs.indices, id: \.self) { index in
|
|
376
|
+
SwiftUI.Button(action: { onPress(index) }) {
|
|
377
|
+
cardItem(tab: tabs[index], isActive: false)
|
|
378
|
+
.padding(.horizontal, Spacing.S)
|
|
379
|
+
.frame(width: itemWidth, height: cardTabHeight)
|
|
380
|
+
.background(Colors.black02)
|
|
381
|
+
.clipShape(UnstyledRoundedRectangle(topLeft: Radius.M, topRight: Radius.M))
|
|
382
|
+
.contentShape(Rectangle())
|
|
383
|
+
}
|
|
384
|
+
.buttonStyle(ActiveOpacityButtonStyle())
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
if let active = tabs[safe: selectedIndex] {
|
|
389
|
+
activeCard(active, itemWidth: itemWidth)
|
|
373
390
|
}
|
|
374
|
-
.buttonStyle(ActiveOpacityButtonStyle())
|
|
375
391
|
}
|
|
392
|
+
.frame(width: geo.size.width, height: cardTabActiveHeight, alignment: .bottomLeading)
|
|
376
393
|
}
|
|
377
|
-
.
|
|
378
|
-
.
|
|
394
|
+
// The raised card overflows the strip into the top `Spacing.XS` margin.
|
|
395
|
+
.frame(height: cardTabActiveHeight)
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
private func activeCard(_ tab: TabViewItem, itemWidth: CGFloat) -> some View {
|
|
399
|
+
let surface = theme.colors.background.surface
|
|
400
|
+
let pathWidth: CGFloat = tabs.count > 2 ? 22 : 28
|
|
401
|
+
let isFirst = selectedIndex == 0
|
|
402
|
+
let isLast = selectedIndex == tabs.count - 1
|
|
403
|
+
|
|
404
|
+
return HStack(alignment: .bottom, spacing: 0) {
|
|
405
|
+
// Each ear is nudged 8pt under the card so the join has no seam.
|
|
406
|
+
if !isFirst { cardEar(mirrored: true, width: pathWidth, color: surface).offset(x: 8) }
|
|
407
|
+
SwiftUI.Button(action: { onPress(selectedIndex) }) {
|
|
408
|
+
cardItem(tab: tab, isActive: true)
|
|
409
|
+
.padding(.horizontal, tabs.count == 3 ? Spacing.S : Spacing.M)
|
|
410
|
+
.frame(width: itemWidth, height: cardTabActiveHeight)
|
|
411
|
+
.background(surface)
|
|
412
|
+
.clipShape(UnstyledRoundedRectangle(topLeft: Radius.M, topRight: Radius.M))
|
|
413
|
+
.contentShape(Rectangle())
|
|
414
|
+
}
|
|
415
|
+
.buttonStyle(ActiveOpacityButtonStyle())
|
|
416
|
+
if !isLast { cardEar(mirrored: false, width: pathWidth, color: surface).offset(x: -8) }
|
|
417
|
+
}
|
|
418
|
+
.offset(x: itemWidth * CGFloat(selectedIndex) - (isFirst ? 0 : pathWidth))
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
private func cardEar(mirrored: Bool, width: CGFloat, color: Color) -> some View {
|
|
422
|
+
CardTabEarShape(mirrored: mirrored)
|
|
423
|
+
.fill(color)
|
|
424
|
+
.frame(width: width, height: cardTabActiveHeight)
|
|
425
|
+
.clipped()
|
|
426
|
+
.allowsHitTesting(false)
|
|
379
427
|
}
|
|
380
428
|
|
|
381
429
|
@ViewBuilder
|
|
382
|
-
private func cardItem(tab: TabViewItem, isActive: Bool
|
|
430
|
+
private func cardItem(tab: TabViewItem, isActive: Bool) -> some View {
|
|
431
|
+
let color = isActive ? selectedColor : unselectedColor
|
|
383
432
|
HStack(spacing: 0) {
|
|
384
433
|
if let renderIcon = tab.renderIcon {
|
|
385
434
|
renderIcon(isActive)
|
|
386
435
|
Spacer().frame(width: Spacing.XS)
|
|
387
436
|
} else if let icon = tab.icon {
|
|
388
|
-
Icon(source: icon, size: 18, color:
|
|
437
|
+
Icon(source: icon, size: 18, color: color)
|
|
389
438
|
Spacer().frame(width: Spacing.XS)
|
|
390
439
|
}
|
|
391
440
|
MomoText(
|
|
392
441
|
tab.title,
|
|
393
442
|
typography: isActive ? .headerSSemibold : .bodyDefaultRegular,
|
|
394
|
-
color:
|
|
443
|
+
color: color
|
|
395
444
|
)
|
|
396
445
|
.lineLimit(1)
|
|
397
446
|
|
|
398
447
|
tabBadge(tab)
|
|
399
448
|
}
|
|
400
|
-
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/// react-kits' 28x44 ear path, in points; not scaled to the frame, which clips it at a 22pt width.
|
|
453
|
+
private struct CardTabEarShape: Shape {
|
|
454
|
+
let mirrored: Bool
|
|
455
|
+
|
|
456
|
+
func path(in rect: CGRect) -> Path {
|
|
457
|
+
var path = Path()
|
|
458
|
+
path.move(to: CGPoint(x: 0, y: 0))
|
|
459
|
+
path.addLine(to: CGPoint(x: 0.60765, y: 0))
|
|
460
|
+
path.addCurve(
|
|
461
|
+
to: CGPoint(x: 12.4602, y: 10.0244),
|
|
462
|
+
control1: CGPoint(x: 6.47582, y: 0),
|
|
463
|
+
control2: CGPoint(x: 11.4819, y: 4.23831)
|
|
464
|
+
)
|
|
465
|
+
path.addCurve(
|
|
466
|
+
to: CGPoint(x: 16.6925, y: 34),
|
|
467
|
+
control1: CGPoint(x: 13.9248, y: 18.6872),
|
|
468
|
+
control2: CGPoint(x: 15.9294, y: 30.37)
|
|
469
|
+
)
|
|
470
|
+
path.addCurve(
|
|
471
|
+
to: CGPoint(x: 27.9996, y: 44),
|
|
472
|
+
control1: CGPoint(x: 17.9536, y: 40),
|
|
473
|
+
control2: CGPoint(x: 22.259, y: 44)
|
|
474
|
+
)
|
|
475
|
+
path.addLine(to: CGPoint(x: 0, y: 44))
|
|
476
|
+
path.closeSubpath()
|
|
477
|
+
return mirrored
|
|
478
|
+
? path.applying(CGAffineTransform(a: -1, b: 0, c: 0, d: 1, tx: rect.width, ty: 0))
|
|
479
|
+
: path
|
|
401
480
|
}
|
|
402
481
|
}
|
|
403
482
|
|
|
@@ -426,6 +505,8 @@ private struct TabItemView: View {
|
|
|
426
505
|
rowBody
|
|
427
506
|
}
|
|
428
507
|
}
|
|
508
|
+
// Equal-width bars hit-test the whole cell, like Compose's weighted clickable.
|
|
509
|
+
.frame(maxWidth: scrollable ? nil : .infinity)
|
|
429
510
|
.contentShape(Rectangle())
|
|
430
511
|
}
|
|
431
512
|
.buttonStyle(ActiveOpacityButtonStyle())
|
package/ios/Tag/Tag.swift
CHANGED
|
@@ -45,26 +45,37 @@ public struct Tag: View {
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
// RN only accepts the `_03` palette as a custom tag color.
|
|
49
|
+
private static let customColors: [Color] = [
|
|
50
|
+
Colors.black03, Colors.pink03, Colors.violet03, Colors.indigo03,
|
|
51
|
+
Colors.blue03, Colors.mint03, Colors.green03, Colors.lime03,
|
|
52
|
+
Colors.yellow03, Colors.gold03, Colors.orange03, Colors.red03
|
|
53
|
+
]
|
|
54
|
+
|
|
48
55
|
private let label: String
|
|
49
56
|
private let icon: String?
|
|
50
57
|
private let color: TagColor
|
|
51
58
|
private let size: TagSize
|
|
59
|
+
private let customColor: Color?
|
|
52
60
|
|
|
53
61
|
public init(
|
|
54
62
|
label: String = "Label",
|
|
55
63
|
icon: String? = nil,
|
|
56
64
|
color: TagColor = .default,
|
|
57
|
-
size: TagSize = .large
|
|
65
|
+
size: TagSize = .large,
|
|
66
|
+
customColor: Color? = nil
|
|
58
67
|
) {
|
|
59
68
|
self.label = label
|
|
60
69
|
self.icon = icon
|
|
61
70
|
self.color = color
|
|
62
71
|
self.size = size
|
|
72
|
+
self.customColor = customColor
|
|
63
73
|
}
|
|
64
74
|
|
|
65
75
|
public var body: some View {
|
|
66
|
-
let
|
|
67
|
-
let
|
|
76
|
+
let custom = customColor.flatMap { Self.customColors.contains($0) ? $0 : nil }
|
|
77
|
+
let tagColor = custom ?? color.backgroundColor
|
|
78
|
+
let labelColor = custom != nil ? Colors.black01 : color.textColor
|
|
68
79
|
|
|
69
80
|
HStack(spacing: 0) {
|
|
70
81
|
if let icon {
|
|
@@ -75,7 +86,7 @@ public struct Tag: View {
|
|
|
75
86
|
.frame(height: fontScale(size.height))
|
|
76
87
|
.padding(.horizontal, Spacing.S)
|
|
77
88
|
.background(
|
|
78
|
-
RoundedRectangle(cornerRadius: Radius.S
|
|
89
|
+
RoundedRectangle(cornerRadius: Radius.S)
|
|
79
90
|
.fill(tagColor)
|
|
80
91
|
)
|
|
81
92
|
}
|
|
@@ -57,7 +57,8 @@ private extension View {
|
|
|
57
57
|
func containerBackground (_ type: String, _ useBackground: Bool, _ backgroundColor: Color) -> some View {
|
|
58
58
|
Group {
|
|
59
59
|
if (useBackground && type != "icon") {
|
|
60
|
-
|
|
60
|
+
// Same shape as the border, or the square corners (and the shadow) show around it.
|
|
61
|
+
self.background(RoundedRectangle(cornerRadius: 8).fill(backgroundColor))
|
|
61
62
|
} else {
|
|
62
63
|
self
|
|
63
64
|
}
|