@momo-kits/native-kits 0.163.1-beta.2-debug → 0.163.1-beta.20-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 +112 -0
- package/CLAUDE.md +1 -1
- package/compose/build.gradle.kts +2 -1
- package/compose/build.gradle.kts.backup +1 -0
- package/compose/compose.podspec +1 -1
- 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 +30 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +8 -10
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +2 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +3 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +56 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +11 -9
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +0 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +40 -55
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +69 -26
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +5 -5
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +3 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +21 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +3 -6
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +19 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitFontScale.kt +22 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +28 -21
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +50 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +25 -22
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +37 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +68 -22
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +7 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +112 -115
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +15 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +33 -9
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +6 -5
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +3 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +2 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +0 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +23 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +9 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +11 -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 +26 -3
- package/gradle/libs.versions.toml +2 -0
- package/gradle.properties +1 -1
- package/ios/Application/ApplicationEnvironment.swift +15 -3
- package/ios/Application/Components.swift +36 -30
- package/ios/Application/FloatingButton.swift +10 -9
- package/ios/Application/Localize.swift +309 -0
- package/ios/Application/MaxApi.swift +18 -0
- package/ios/Application/Navigation/BottomTab/BottomTab.swift +104 -0
- package/ios/Application/Navigation/BottomTab/BottomTabBar.swift +215 -0
- package/ios/Application/Navigation/BottomTab/CurvedContainer.swift +65 -0
- package/ios/Application/Navigation/HeaderBackProps.swift +66 -0
- package/ios/Application/Navigation/HeaderTitle.swift +57 -0
- package/ios/Application/Navigation/HeaderUser.swift +209 -0
- package/ios/Application/Navigation/NavigationContainer.swift +203 -0
- package/ios/Application/Navigation/NavigationOptions.swift +109 -0
- package/ios/Application/Navigation/Navigator.swift +385 -0
- package/ios/Application/Navigation/Overplay/BottomSheet.swift +256 -0
- package/ios/Application/Navigation/Overplay/ModalScreen.swift +74 -0
- package/ios/Application/Navigation/Overplay/SnackBar.swift +144 -0
- package/ios/Application/Navigation/Tracking/ScreenTracker.swift +117 -0
- package/ios/Application/Navigation/component/Header.swift +178 -0
- package/ios/Application/Navigation/component/HeaderBackground.swift +83 -0
- package/ios/Application/Navigation/component/HeaderColor.swift +65 -0
- package/ios/Application/Navigation/component/HeaderRightWidthKey.swift +11 -0
- package/ios/Application/Navigation/component/NavigationHeaderRight.swift +196 -0
- package/ios/Application/Screen.swift +2 -1
- package/ios/Application/StackScreen.swift +501 -0
- package/ios/Avatar/Avatar.swift +193 -0
- package/ios/Badge/Badge.swift +11 -14
- package/ios/Badge/BadgeRibbon.swift +91 -17
- package/ios/BaselineView/BaselineView.swift +163 -0
- package/ios/Button/Button.swift +137 -28
- package/ios/Carousel/Carousel.swift +196 -0
- package/ios/Checkbox/Checkbox.swift +23 -28
- package/ios/Chip/Chip.swift +56 -33
- package/ios/Collapse/Collapse.swift +192 -0
- package/ios/Colors+Radius+Spacing/Colors.swift +20 -17
- package/ios/Colors+Radius+Spacing/Spacing.swift +3 -1
- package/ios/Colors+Radius+Spacing/Theme.swift +295 -0
- package/ios/DateTimePicker/DateTimePicker.swift +212 -0
- package/ios/DateTimePicker/DateTimePickerTypes.swift +55 -0
- package/ios/DateTimePicker/DateTimePickerUtils.swift +167 -0
- package/ios/DateTimePicker/WheelPicker.swift +165 -0
- package/ios/Divider/Divider.swift +16 -0
- package/ios/Extensions/ActiveOpacityButtonStyle.swift +14 -0
- package/ios/Extensions/Color++.swift +32 -0
- package/ios/Icon/Icon.swift +10 -1
- package/ios/IconButton/IconButton.swift +140 -0
- package/ios/Image/Image.swift +16 -3
- package/ios/Information/Information.swift +3 -1
- package/ios/Input/ErrorView.swift +3 -1
- package/ios/Input/Input.swift +72 -33
- package/ios/Input/InputPhoneNumber.swift +33 -21
- package/ios/Input/InputSearch.swift +107 -48
- package/ios/Input/InputTextArea.swift +134 -64
- package/ios/InputDropDown/InputDropDown.swift +201 -0
- package/ios/InputMoney/InputMoney.swift +347 -0
- package/ios/InputOTP/InputOTP.swift +210 -0
- package/ios/Loader/Loader.swift +113 -0
- package/ios/MoMoUIKits.podspec +5 -0
- 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 +11 -20
- package/ios/Popup/PopupInput.swift +2 -8
- package/ios/Popup/PopupNotify.swift +218 -0
- package/ios/Popup/PopupPromotion.swift +5 -3
- package/ios/ProgressInfo/ProgressInfo.swift +296 -0
- package/ios/Radio/Radio.swift +69 -0
- package/ios/Rating/Rating.swift +82 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/AccentColor.colorset/Contents.json +11 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/Background.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/Border.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/Card.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/Contents.json +6 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/Error.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/Primary.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/PrimaryDark.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/PrimaryLight.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/Secondary.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/Success.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/Text.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/TextSecondary.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/Contents.json +9 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-default.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-disable.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-pressed.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-selected.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-surface.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/background-tonal.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/border-default.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/border-disable.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/gradient.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/primary.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/secondary.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-container.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-primary.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/success-secondary.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-default.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-disable.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-hint.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/ThemeColors/text-secondary.colorset/Contents.json +38 -0
- package/ios/Resources/MoMoUIKitsColors.xcassets/Warning.colorset/Contents.json +38 -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 +467 -0
- package/ios/SuggestAction/SuggestAction.swift +99 -0
- package/ios/Swipeable/SwipeCell.swift +187 -0
- package/ios/Swipeable/SwipeCellModel.swift +21 -0
- package/ios/Switch/Switch.swift +53 -28
- package/ios/TabView/TabView.swift +534 -0
- package/ios/Tag/Tag.swift +98 -0
- package/ios/Template/TrustBanner/TrustBanner.swift +7 -8
- package/ios/Title/Title.swift +269 -0
- package/ios/Tooltip/Tooltip.swift +485 -0
- package/ios/Typography/FontScaleStore.swift +19 -0
- package/ios/Typography/Text.swift +86 -17
- package/ios/Typography/Typography.swift +12 -14
- package/ios/Uploader/Uploader.swift +174 -0
- package/ios/native-kits.podspec +61 -8
- package/ios-demo/MoMoUIKitsDemo.podspec +20 -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 +24 -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 +64 -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 +279 -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/LocalizeDemo.swift +188 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/NavigationDemo.swift +229 -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 +51 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoModels.swift +15 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoRegistry.swift +73 -0
- package/local.properties +2 -2
- package/package.json +1 -1
- package/publish.sh +53 -0
- package/scripts/gen-ios-color.mjs +136 -0
- package/example/ios/Example.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
- package/example/ios/Example.xcworkspace/xcuserdata/huynhdung.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/example/ios/Example.xcworkspace/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +0 -5
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/MoMoUIKits.xcscheme +0 -58
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/Pods-Example.xcscheme +0 -58
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SDWebImage.xcscheme +0 -58
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SDWebImageSwiftUI.xcscheme +0 -58
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SkeletonUI.xcscheme +0 -58
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +0 -46
- package/ios/Application/FontScaleStore.swift +0 -59
package/ios/Badge/Badge.swift
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import SwiftUI
|
|
2
2
|
|
|
3
3
|
public struct Badge: View {
|
|
4
|
+
@Environment(\.appTheme) private var theme
|
|
4
5
|
let label: String
|
|
5
6
|
let backgroundColor: Color?
|
|
6
7
|
|
|
@@ -38,24 +39,21 @@ public struct Badge: View {
|
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
private var badgeColor: Color {
|
|
41
|
-
//
|
|
42
|
-
|
|
42
|
+
// Default colors based on label type
|
|
43
|
+
let defaultColor: Color = isNumber(label)
|
|
44
|
+
? theme.colors.error.primary
|
|
45
|
+
: theme.colors.warning.primary
|
|
46
|
+
|
|
47
|
+
// Mirror Compose: only apply backgroundColor when it is one of the
|
|
48
|
+
// allowed primaryColors; otherwise fall back to the label-based default.
|
|
49
|
+
if let bgColor = backgroundColor, primaryColors.contains(bgColor) {
|
|
43
50
|
return bgColor
|
|
44
51
|
}
|
|
45
|
-
|
|
46
|
-
// Otherwise, use default colors based on label type
|
|
47
|
-
if isNumber(label) {
|
|
48
|
-
return Colors.red03 // error.primary
|
|
49
|
-
} else {
|
|
50
|
-
return Colors.orange03 // warning.primary
|
|
51
|
-
}
|
|
52
|
+
return defaultColor
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
public var body: some View {
|
|
55
|
-
|
|
56
|
-
.font(.system(size: scaleSize(10), weight: .bold))
|
|
57
|
-
.ignoreBoldTextSetting()
|
|
58
|
-
.foregroundColor(Colors.black01)
|
|
56
|
+
MomoText(formatTitle(label), typography: .actionXxsBold, color: Colors.black01)
|
|
59
57
|
.padding(.horizontal, Spacing.XS)
|
|
60
58
|
.frame(minWidth: scaleSize(16), minHeight: scaleSize(16))
|
|
61
59
|
.background(badgeColor)
|
|
@@ -83,4 +81,3 @@ struct Badge_Previews: PreviewProvider {
|
|
|
83
81
|
}
|
|
84
82
|
}
|
|
85
83
|
#endif
|
|
86
|
-
|
|
@@ -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,22 +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
|
-
.ignoreBoldTextSetting()
|
|
142
|
-
.foregroundColor(Colors.black01)
|
|
143
|
-
.lineLimit(1)
|
|
142
|
+
MomoText(label, typography: .labelXsMedium, color: Colors.black01, maxLines: 1)
|
|
144
143
|
.rotationEffect(rotation)
|
|
145
144
|
}
|
|
146
145
|
.frame(height: RibbonConstants.roundHeight)
|
|
@@ -156,13 +155,9 @@ public struct BadgeRibbon: View {
|
|
|
156
155
|
)
|
|
157
156
|
}
|
|
158
157
|
|
|
159
|
-
private
|
|
158
|
+
private func skewContent(backgroundColor: Color) -> some View {
|
|
160
159
|
HStack(spacing: 0) {
|
|
161
|
-
|
|
162
|
-
.font(.system(size: scaleSize(12), weight: .medium))
|
|
163
|
-
.ignoreBoldTextSetting()
|
|
164
|
-
.foregroundColor(Colors.black01)
|
|
165
|
-
.lineLimit(1)
|
|
160
|
+
MomoText(label, typography: .labelXsMedium, color: Colors.black01, maxLines: 1)
|
|
166
161
|
.rotationEffect(rotation)
|
|
167
162
|
.frame(height: RibbonConstants.skewBodyHeight)
|
|
168
163
|
.padding(.horizontal, 8)
|
|
@@ -204,6 +199,86 @@ public struct BadgeRibbon: View {
|
|
|
204
199
|
}
|
|
205
200
|
}
|
|
206
201
|
|
|
202
|
+
/// Ported from Compose's `RoundedBadgeRibbon` (BadgeRibbon.kt:164-326): a canvas-drawn
|
|
203
|
+
/// ribbon shape sized to its text, mirrored per corner via scaleX/scaleY (never an actual
|
|
204
|
+
/// rotation) — the label gets the same scale applied a second time so it stays right-reading
|
|
205
|
+
/// while only the ribbon shape flips.
|
|
206
|
+
public struct RoundedBadgeRibbon: View {
|
|
207
|
+
let text: String
|
|
208
|
+
let position: RibbonPosition
|
|
209
|
+
|
|
210
|
+
public init(text: String = "Label", position: RibbonPosition = .topLeft) {
|
|
211
|
+
self.text = text
|
|
212
|
+
self.position = position
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
private var scale: (x: CGFloat, y: CGFloat) {
|
|
216
|
+
switch position {
|
|
217
|
+
case .topLeft: return (-1, 1)
|
|
218
|
+
case .topRight: return (1, 1)
|
|
219
|
+
case .bottomRight: return (1, -1)
|
|
220
|
+
case .bottomLeft: return (-1, -1)
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
private var measuredTextSize: CGSize {
|
|
225
|
+
let fontSize = scaleSize(TypographyStyle.labelXsMedium.fontSize)
|
|
226
|
+
let font = UIFont.systemFont(ofSize: fontSize, weight: .medium)
|
|
227
|
+
return text.size(withAttributes: [.font: font])
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
public var body: some View {
|
|
231
|
+
let textSize = measuredTextSize
|
|
232
|
+
let minRibbonHeight = max(textSize.height * 1.2, 16)
|
|
233
|
+
let padding = minRibbonHeight / 4
|
|
234
|
+
let badgeHeight = minRibbonHeight + padding
|
|
235
|
+
let badgeWidth = max(textSize.width + padding * 2, 28)
|
|
236
|
+
|
|
237
|
+
ZStack {
|
|
238
|
+
Canvas { context, size in
|
|
239
|
+
let ribbonHeight = size.height - padding
|
|
240
|
+
let cornerRadius = (badgeHeight - padding) / 2
|
|
241
|
+
let mainColor = Colors.orange03
|
|
242
|
+
let tailColor = Colors.red01
|
|
243
|
+
|
|
244
|
+
let headWidth: CGFloat = 4
|
|
245
|
+
// Kotlin computes `leftSectionWidth` + `middleSectionWidth` here, but those
|
|
246
|
+
// cancel algebraically to `width - headWidth` — kept as the direct result.
|
|
247
|
+
let rightX = size.width - headWidth
|
|
248
|
+
|
|
249
|
+
let leftMiddlePath = RoundedCorners(topLeft: cornerRadius, topRight: 0, bottomLeft: cornerRadius, bottomRight: 0)
|
|
250
|
+
.path(in: CGRect(x: 0, y: 0, width: rightX + 1, height: ribbonHeight))
|
|
251
|
+
context.fill(leftMiddlePath, with: .color(mainColor))
|
|
252
|
+
|
|
253
|
+
let headPath = RoundedCorners(topLeft: 0, topRight: cornerRadius, bottomLeft: 0, bottomRight: 0)
|
|
254
|
+
.path(in: CGRect(x: rightX, y: 0, width: headWidth, height: ribbonHeight))
|
|
255
|
+
context.fill(headPath, with: .color(mainColor))
|
|
256
|
+
|
|
257
|
+
let halfHeadWidth = headWidth / 2
|
|
258
|
+
let tailStartX = rightX + headWidth - halfHeadWidth
|
|
259
|
+
let tailY = ribbonHeight
|
|
260
|
+
let tailHeight = padding
|
|
261
|
+
|
|
262
|
+
context.fill(
|
|
263
|
+
Path(CGRect(x: tailStartX, y: tailY, width: halfHeadWidth, height: halfHeadWidth)),
|
|
264
|
+
with: .color(mainColor)
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
let tailRightPath = RoundedCorners(topLeft: 0, topRight: tailHeight, bottomLeft: 0, bottomRight: tailHeight)
|
|
268
|
+
.path(in: CGRect(x: tailStartX, y: tailY, width: halfHeadWidth, height: tailHeight))
|
|
269
|
+
context.fill(tailRightPath, with: .color(tailColor))
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
MomoText(text, typography: .labelXsMedium, color: Colors.black01, maxLines: 1)
|
|
273
|
+
.padding(.bottom, padding)
|
|
274
|
+
.padding(.horizontal, padding / 2)
|
|
275
|
+
.scaleEffect(x: scale.x, y: scale.y)
|
|
276
|
+
}
|
|
277
|
+
.frame(width: badgeWidth, height: badgeHeight)
|
|
278
|
+
.scaleEffect(x: scale.x, y: scale.y)
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
207
282
|
// MARK: - Constants
|
|
208
283
|
private struct RibbonConstants {
|
|
209
284
|
static let ribbonHeight: CGFloat = 20
|
|
@@ -241,4 +316,3 @@ struct BadgeRibbon_Previews: PreviewProvider {
|
|
|
241
316
|
}
|
|
242
317
|
}
|
|
243
318
|
#endif
|
|
244
|
-
|
|
@@ -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
|
}
|
|
@@ -111,12 +123,12 @@ extension ButtonSize {
|
|
|
111
123
|
case .large: return .actionDefaultBold
|
|
112
124
|
case .medium: return .actionSBold
|
|
113
125
|
case .small: return .actionXsBold
|
|
114
|
-
default : return .actionDefaultBold
|
|
115
126
|
}
|
|
116
127
|
}
|
|
117
128
|
}
|
|
118
129
|
|
|
119
130
|
public struct Button: View {
|
|
131
|
+
@Environment(\.appTheme) private var theme
|
|
120
132
|
var title: String
|
|
121
133
|
var action: () -> Void
|
|
122
134
|
var type: ButtonType
|
|
@@ -125,6 +137,7 @@ public struct Button: View {
|
|
|
125
137
|
var iconRight: AnyView?
|
|
126
138
|
var isFull: Bool
|
|
127
139
|
var loading: Bool
|
|
140
|
+
var useTintColor: Bool
|
|
128
141
|
|
|
129
142
|
public init(
|
|
130
143
|
title: String = "",
|
|
@@ -134,7 +147,8 @@ public struct Button: View {
|
|
|
134
147
|
iconLeft: AnyView? = nil,
|
|
135
148
|
iconRight: AnyView? = nil,
|
|
136
149
|
isFull: Bool = true,
|
|
137
|
-
loading: Bool = false
|
|
150
|
+
loading: Bool = false,
|
|
151
|
+
useTintColor: Bool = true
|
|
138
152
|
) {
|
|
139
153
|
self.title = title
|
|
140
154
|
self.action = action
|
|
@@ -144,6 +158,36 @@ public struct Button: View {
|
|
|
144
158
|
self.iconRight = iconRight
|
|
145
159
|
self.isFull = isFull
|
|
146
160
|
self.loading = loading
|
|
161
|
+
self.useTintColor = useTintColor
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/// Mirrors Kotlin's `Button(iconLeft: String, iconRight: String, ...)`, which resolves
|
|
165
|
+
/// icons by design-system source name through the shared `Icon` component rather than
|
|
166
|
+
/// a caller-supplied view. `iconLeft` is required here (unlike Kotlin's `= ""` default)
|
|
167
|
+
/// solely to keep this initializer unambiguous alongside the `AnyView`-based one above —
|
|
168
|
+
/// pass `""` explicitly for an icon-right-only button.
|
|
169
|
+
public init(
|
|
170
|
+
title: String = "Button",
|
|
171
|
+
action: @escaping () -> Void,
|
|
172
|
+
type: ButtonType = .primary,
|
|
173
|
+
size: ButtonSize = .large,
|
|
174
|
+
iconLeft: String,
|
|
175
|
+
iconRight: String = "",
|
|
176
|
+
isFull: Bool = true,
|
|
177
|
+
loading: Bool = false,
|
|
178
|
+
useTintColor: Bool = true
|
|
179
|
+
) {
|
|
180
|
+
self.init(
|
|
181
|
+
title: title,
|
|
182
|
+
action: action,
|
|
183
|
+
type: type,
|
|
184
|
+
size: size,
|
|
185
|
+
iconLeft: iconLeft.isEmpty ? nil : AnyView(Icon(source: iconLeft)),
|
|
186
|
+
iconRight: iconRight.isEmpty ? nil : AnyView(Icon(source: iconRight)),
|
|
187
|
+
isFull: isFull,
|
|
188
|
+
loading: loading,
|
|
189
|
+
useTintColor: useTintColor
|
|
190
|
+
)
|
|
147
191
|
}
|
|
148
192
|
|
|
149
193
|
private func shouldLoadingOnLeft(_ left: AnyView?, _ right: AnyView?) -> Bool {
|
|
@@ -160,14 +204,15 @@ public struct Button: View {
|
|
|
160
204
|
|
|
161
205
|
public var body: some View {
|
|
162
206
|
let loadingOnLeft = shouldLoadingOnLeft(iconLeft, iconRight)
|
|
207
|
+
let isEnabled = type != .disabled && !loading
|
|
163
208
|
|
|
164
|
-
let bg = type.backgroundColor(loading: loading)
|
|
165
|
-
let fg = type.contentColor(loading: loading)
|
|
166
|
-
let border = type.borderColor
|
|
209
|
+
let bg = type.backgroundColor(loading: loading, theme: theme)
|
|
210
|
+
let fg = type.contentColor(loading: loading, theme: theme)
|
|
211
|
+
let border = type.borderColor(theme: theme)
|
|
167
212
|
let borderWidth = type.borderWidth
|
|
168
213
|
|
|
169
214
|
SwiftUI.Button(action: {
|
|
170
|
-
if
|
|
215
|
+
if isEnabled {
|
|
171
216
|
action()
|
|
172
217
|
}
|
|
173
218
|
}) {
|
|
@@ -178,7 +223,7 @@ public struct Button: View {
|
|
|
178
223
|
.colorMultiply(fg)
|
|
179
224
|
|
|
180
225
|
} else if let iconLeft = iconLeft {
|
|
181
|
-
iconLeft
|
|
226
|
+
tintedIcon(iconLeft, color: fg)
|
|
182
227
|
}
|
|
183
228
|
|
|
184
229
|
MomoText(title, typography: size.typographyStyle, color: fg)
|
|
@@ -191,20 +236,84 @@ public struct Button: View {
|
|
|
191
236
|
.colorMultiply(fg)
|
|
192
237
|
|
|
193
238
|
} else if let iconRight = iconRight {
|
|
194
|
-
iconRight
|
|
239
|
+
tintedIcon(iconRight, color: fg)
|
|
195
240
|
}
|
|
196
241
|
}
|
|
197
242
|
.frame(maxWidth: isFull ? .infinity : nil)
|
|
198
243
|
.padding(.horizontal, size.padding)
|
|
199
244
|
.frame(height: size.height)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
245
|
+
}
|
|
246
|
+
.buttonStyle(ButtonPressFeedbackStyle(
|
|
247
|
+
isEnabled: isEnabled,
|
|
248
|
+
background: bg,
|
|
249
|
+
border: border,
|
|
250
|
+
borderWidth: borderWidth,
|
|
251
|
+
radius: size.radius,
|
|
252
|
+
height: size.height,
|
|
253
|
+
isFull: isFull
|
|
254
|
+
))
|
|
255
|
+
.disabled(!isEnabled)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
@ViewBuilder
|
|
259
|
+
private func tintedIcon(_ icon: AnyView, color: Color) -> some View {
|
|
260
|
+
if useTintColor {
|
|
261
|
+
icon
|
|
262
|
+
.frame(width: size.iconSize, height: size.iconSize)
|
|
263
|
+
.colorMultiply(color)
|
|
264
|
+
} else {
|
|
265
|
+
icon
|
|
266
|
+
.frame(width: size.iconSize, height: size.iconSize)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/// Mirrors Compose's press feedback: the background shrinks via an animated
|
|
272
|
+
/// horizontal inset while the content fades, rather than a plain opacity dim on
|
|
273
|
+
/// the whole button (matching `animatedPadding`/`alpha` in Button.kt).
|
|
274
|
+
private struct ButtonPressFeedbackStyle: ButtonStyle {
|
|
275
|
+
let isEnabled: Bool
|
|
276
|
+
let background: Color
|
|
277
|
+
let border: Color?
|
|
278
|
+
let borderWidth: CGFloat
|
|
279
|
+
let radius: CGFloat
|
|
280
|
+
let height: CGFloat
|
|
281
|
+
let isFull: Bool
|
|
282
|
+
|
|
283
|
+
func makeBody(configuration: Configuration) -> some View {
|
|
284
|
+
let pressed = configuration.isPressed && isEnabled
|
|
285
|
+
|
|
286
|
+
configuration.label
|
|
287
|
+
.modifier(HugContentOnLegacyOS(isFull: isFull))
|
|
288
|
+
.opacity(pressed ? 0.5 : 1)
|
|
289
|
+
.background(
|
|
290
|
+
RoundedRectangle(cornerRadius: radius)
|
|
291
|
+
.fill(background)
|
|
292
|
+
.overlay(
|
|
293
|
+
RoundedRectangle(cornerRadius: radius)
|
|
294
|
+
.strokeBorder(border ?? .clear, lineWidth: border != nil ? borderWidth : 0)
|
|
295
|
+
)
|
|
296
|
+
.padding(.horizontal, pressed ? 2 : 0)
|
|
204
297
|
)
|
|
205
|
-
.
|
|
206
|
-
.
|
|
298
|
+
.frame(height: height)
|
|
299
|
+
.clipShape(RoundedRectangle(cornerRadius: radius))
|
|
300
|
+
.animation(.easeInOut(duration: 0.1), value: pressed)
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/// `ButtonStyleConfiguration.Label` is greedy on iOS 16 and earlier — it accepts
|
|
305
|
+
/// the full proposed width, so the background drawn in `makeBody` stretches past
|
|
306
|
+
/// the content even when `isFull == false`. iOS 17 fixed the label to hug its
|
|
307
|
+
/// content, so only legacy OSes need the `fixedSize` clamp (kept off on 17+ to
|
|
308
|
+
/// preserve tail truncation of long titles).
|
|
309
|
+
private struct HugContentOnLegacyOS: ViewModifier {
|
|
310
|
+
let isFull: Bool
|
|
311
|
+
|
|
312
|
+
func body(content: Content) -> some View {
|
|
313
|
+
if #available(iOS 17.0, *) {
|
|
314
|
+
content
|
|
315
|
+
} else {
|
|
316
|
+
content.fixedSize(horizontal: !isFull, vertical: false)
|
|
207
317
|
}
|
|
208
|
-
.disabled(type == .disabled || loading)
|
|
209
318
|
}
|
|
210
319
|
}
|