@momo-kits/native-kits 0.163.1-beta.3-debug → 0.163.1-beta.5-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 +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/commonMain/kotlin/vn/momo/kits/application/Context.kt +8 -10
- 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/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/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/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/navigation/Navigation.kt +4 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +112 -115
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +11 -6
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +3 -4
- 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/platform/OsFontScale.kt +9 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +66 -0
- package/gradle/libs.versions.toml +2 -0
- package/gradle.properties +1 -1
- package/ios/Application/ApplicationEnvironment.swift +11 -1
- package/ios/Application/Components.swift +34 -44
- package/ios/Application/FloatingButton.swift +10 -9
- package/ios/Application/HeaderRight.swift +79 -45
- package/ios/Application/Navigation/BottomTab/BottomTab.swift +103 -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 +176 -0
- package/ios/Application/Navigation/NavigationOptions.swift +109 -0
- package/ios/Application/Navigation/Navigator.swift +364 -0
- package/ios/Application/Navigation/Overplay/BottomSheet.swift +188 -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/Screen.swift +2 -1
- package/ios/Application/StackScreen.swift +453 -0
- package/ios/Avatar/Avatar.swift +193 -0
- package/ios/Badge/Badge.swift +11 -14
- package/ios/Badge/BadgeRibbon.swift +12 -21
- package/ios/BaselineView/BaselineView.swift +163 -0
- package/ios/Button/Button.swift +61 -22
- package/ios/Carousel/Carousel.swift +181 -0
- package/ios/Checkbox/Checkbox.swift +14 -13
- package/ios/Chip/Chip.swift +23 -9
- package/ios/Collapse/Collapse.swift +182 -0
- package/ios/Colors+Radius+Spacing/Colors.swift +12 -12
- 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/Extensions/Color++.swift +32 -0
- package/ios/Icon/Icon.swift +6 -1
- package/ios/IconButton/IconButton.swift +112 -0
- package/ios/Input/Input.swift +41 -25
- package/ios/Input/InputPhoneNumber.swift +20 -19
- package/ios/Input/InputSearch.swift +100 -47
- package/ios/Input/InputTextArea.swift +66 -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/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 +8 -16
- package/ios/Popup/PopupInput.swift +2 -8
- 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/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 +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/Title/Title.swift +269 -0
- package/ios/Tooltip/Tooltip.swift +482 -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 +183 -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 +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 +278 -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 +51 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoModels.swift +15 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/UIKitsDemoRegistry.swift +73 -0
- package/package.json +1 -1
- package/publish.sh +50 -0
- package/scripts/gen-ios-color.mjs +136 -0
- package/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
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import Combine
|
|
2
|
+
import SwiftUI
|
|
3
|
+
|
|
4
|
+
/// Native SwiftUI port of the Compose `Carousel` component.
|
|
5
|
+
///
|
|
6
|
+
/// Mirrors the Compose API: a paging horizontal carousel driven by an
|
|
7
|
+
/// `itemCount` and a `content` builder that receives the real (modulo) index.
|
|
8
|
+
/// Supports infinite `loop`, `autoplay` with a configurable interval,
|
|
9
|
+
/// inactive-slide `opacity`/`scale` effects, optional `contentPadding`,
|
|
10
|
+
/// snap behavior, and scroll enable/disable. Snap / scroll-index callbacks
|
|
11
|
+
/// report the real item index.
|
|
12
|
+
///
|
|
13
|
+
/// Available iOS 14+ (uses a custom paging ScrollView so behavior is identical
|
|
14
|
+
/// across versions and supports the loop virtualization + transform effects
|
|
15
|
+
/// that `TabView(.page)` cannot express).
|
|
16
|
+
public struct Carousel<Content: View>: View {
|
|
17
|
+
// MARK: Lifecycle
|
|
18
|
+
|
|
19
|
+
public init(
|
|
20
|
+
itemCount: Int,
|
|
21
|
+
loop: Bool = false,
|
|
22
|
+
autoplay: Bool = false,
|
|
23
|
+
autoplayInterval: TimeInterval = 3.0,
|
|
24
|
+
enableSnap: Bool = true,
|
|
25
|
+
scrollEnabled: Bool = true,
|
|
26
|
+
inactiveSlideOpacity: Double = 1.0,
|
|
27
|
+
inactiveSlideScale: Double = 1.0,
|
|
28
|
+
contentPadding: CGFloat = 0,
|
|
29
|
+
onSnapToItem: @escaping (Int) -> Void = { _ in },
|
|
30
|
+
onScrollIndexChanged: @escaping (Int) -> Void = { _ in },
|
|
31
|
+
@ViewBuilder content: @escaping (_ index: Int) -> Content
|
|
32
|
+
) {
|
|
33
|
+
self.itemCount = itemCount
|
|
34
|
+
self.loop = loop
|
|
35
|
+
self.autoplay = autoplay
|
|
36
|
+
self.autoplayInterval = autoplayInterval
|
|
37
|
+
self.enableSnap = enableSnap
|
|
38
|
+
self.scrollEnabled = scrollEnabled
|
|
39
|
+
self.inactiveSlideOpacity = inactiveSlideOpacity
|
|
40
|
+
self.inactiveSlideScale = inactiveSlideScale
|
|
41
|
+
self.contentPadding = contentPadding
|
|
42
|
+
self.onSnapToItem = onSnapToItem
|
|
43
|
+
self.onScrollIndexChanged = onScrollIndexChanged
|
|
44
|
+
self.content = content
|
|
45
|
+
|
|
46
|
+
let virtual = loop ? itemCount * 1000 : itemCount
|
|
47
|
+
let start = loop ? (virtual / 2) - ((virtual / 2) % max(itemCount, 1)) : 0
|
|
48
|
+
self.virtualPageCount = virtual
|
|
49
|
+
_currentPage = State(initialValue: start)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// MARK: Public
|
|
53
|
+
|
|
54
|
+
public var body: some View {
|
|
55
|
+
if itemCount <= 0 {
|
|
56
|
+
EmptyView()
|
|
57
|
+
} else {
|
|
58
|
+
GeometryReader { geo in
|
|
59
|
+
let pageWidth = max(geo.size.width - contentPadding * 2, 1)
|
|
60
|
+
carouselContent(pageWidth: pageWidth, viewportWidth: geo.size.width)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// MARK: Private
|
|
66
|
+
|
|
67
|
+
private let itemCount: Int
|
|
68
|
+
private let loop: Bool
|
|
69
|
+
private let autoplay: Bool
|
|
70
|
+
private let autoplayInterval: TimeInterval
|
|
71
|
+
private let enableSnap: Bool
|
|
72
|
+
private let scrollEnabled: Bool
|
|
73
|
+
private let inactiveSlideOpacity: Double
|
|
74
|
+
private let inactiveSlideScale: Double
|
|
75
|
+
private let contentPadding: CGFloat
|
|
76
|
+
private let onSnapToItem: (Int) -> Void
|
|
77
|
+
private let onScrollIndexChanged: (Int) -> Void
|
|
78
|
+
private let content: (Int) -> Content
|
|
79
|
+
|
|
80
|
+
private let virtualPageCount: Int
|
|
81
|
+
|
|
82
|
+
@State private var currentPage: Int
|
|
83
|
+
@State private var dragOffset: CGFloat = 0
|
|
84
|
+
@State private var isDragging: Bool = false
|
|
85
|
+
@State private var autoplayTick: Int = 0
|
|
86
|
+
|
|
87
|
+
private func realIndex(_ page: Int) -> Int {
|
|
88
|
+
((page % itemCount) + itemCount) % itemCount
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@ViewBuilder
|
|
92
|
+
private func carouselContent(pageWidth: CGFloat, viewportWidth: CGFloat) -> some View {
|
|
93
|
+
let step = pageWidth
|
|
94
|
+
// Offset so the current page is centered within the viewport padding.
|
|
95
|
+
let baseOffset = -CGFloat(currentPage) * step + contentPadding
|
|
96
|
+
|
|
97
|
+
ZStack {
|
|
98
|
+
HStack(spacing: 0) {
|
|
99
|
+
ForEach(0 ..< virtualPageCount, id: \.self) { page in
|
|
100
|
+
slide(page: page, step: step, viewportWidth: viewportWidth)
|
|
101
|
+
.frame(width: pageWidth)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
.offset(x: baseOffset + dragOffset)
|
|
105
|
+
.animation(isDragging ? nil : .easeInOut(duration: 0.25), value: currentPage)
|
|
106
|
+
.frame(width: viewportWidth, alignment: .leading)
|
|
107
|
+
.contentShape(Rectangle())
|
|
108
|
+
.gesture(scrollEnabled ? dragGesture(step: step) : nil)
|
|
109
|
+
}
|
|
110
|
+
.frame(width: viewportWidth)
|
|
111
|
+
.clipped()
|
|
112
|
+
.onReceive(autoplayTimer) { _ in
|
|
113
|
+
guard autoplay, itemCount > 1, !isDragging else { return }
|
|
114
|
+
advance()
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
@ViewBuilder
|
|
119
|
+
private func slide(page: Int, step: CGFloat, viewportWidth: CGFloat) -> some View {
|
|
120
|
+
// Fractional offset of this page from the current page (incl. drag).
|
|
121
|
+
let dragFraction = step > 0 ? -dragOffset / step : 0
|
|
122
|
+
let pageOffset = abs(CGFloat(currentPage - page) + dragFraction)
|
|
123
|
+
let isActive = pageOffset < 0.5
|
|
124
|
+
let scale = isActive ? 1.0 : inactiveSlideScale
|
|
125
|
+
let alpha = isActive ? 1.0 : inactiveSlideOpacity
|
|
126
|
+
|
|
127
|
+
content(realIndex(page))
|
|
128
|
+
.scaleEffect(scale)
|
|
129
|
+
.opacity(alpha)
|
|
130
|
+
.animation(.easeInOut(duration: 0.15), value: isActive)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
private func dragGesture(step: CGFloat) -> some Gesture {
|
|
134
|
+
DragGesture(minimumDistance: 5)
|
|
135
|
+
.onChanged { value in
|
|
136
|
+
isDragging = true
|
|
137
|
+
dragOffset = value.translation.width
|
|
138
|
+
}
|
|
139
|
+
.onEnded { value in
|
|
140
|
+
isDragging = false
|
|
141
|
+
let predicted = value.predictedEndTranslation.width
|
|
142
|
+
let threshold = step / 4
|
|
143
|
+
var target = currentPage
|
|
144
|
+
if enableSnap {
|
|
145
|
+
if predicted < -threshold {
|
|
146
|
+
target = min(currentPage + 1, virtualPageCount - 1)
|
|
147
|
+
} else if predicted > threshold {
|
|
148
|
+
target = max(currentPage - 1, 0)
|
|
149
|
+
}
|
|
150
|
+
} else {
|
|
151
|
+
// Free scroll still settles to nearest page boundary.
|
|
152
|
+
let moved = step > 0 ? Int((-dragOffset / step).rounded()) : 0
|
|
153
|
+
target = min(max(currentPage + moved, 0), virtualPageCount - 1)
|
|
154
|
+
}
|
|
155
|
+
dragOffset = 0
|
|
156
|
+
setPage(target)
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private func advance() {
|
|
161
|
+
let next = currentPage + 1
|
|
162
|
+
if next < virtualPageCount {
|
|
163
|
+
setPage(next)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private func setPage(_ page: Int) {
|
|
168
|
+
let clamped = min(max(page, 0), virtualPageCount - 1)
|
|
169
|
+
let changed = clamped != currentPage
|
|
170
|
+
currentPage = clamped
|
|
171
|
+
if changed {
|
|
172
|
+
let real = realIndex(clamped)
|
|
173
|
+
onSnapToItem(real)
|
|
174
|
+
onScrollIndexChanged(real)
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private var autoplayTimer: Publishers.Autoconnect<Timer.TimerPublisher> {
|
|
179
|
+
Timer.publish(every: autoplayInterval, on: .main, in: .common).autoconnect()
|
|
180
|
+
}
|
|
181
|
+
}
|
|
@@ -2,6 +2,7 @@ import Foundation
|
|
|
2
2
|
import SwiftUI
|
|
3
3
|
|
|
4
4
|
public struct Checkbox: View{
|
|
5
|
+
@Environment(\.appTheme) private var theme
|
|
5
6
|
@Binding var checked: Bool
|
|
6
7
|
var disabled: Bool
|
|
7
8
|
var onChange: ((Bool)->Void)?
|
|
@@ -37,11 +38,11 @@ public struct Checkbox: View{
|
|
|
37
38
|
)
|
|
38
39
|
|
|
39
40
|
if checked {
|
|
40
|
-
Image(systemName: indeterminate ? "minus
|
|
41
|
+
Image(systemName: indeterminate ? "minus" : "checkmark")
|
|
41
42
|
.resizable()
|
|
42
|
-
.
|
|
43
|
-
.
|
|
44
|
-
.frame(width:
|
|
43
|
+
.scaledToFit()
|
|
44
|
+
.foregroundColor(Colors.black01)
|
|
45
|
+
.frame(width: 12, height: 12)
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
48
|
|
|
@@ -53,28 +54,28 @@ public struct Checkbox: View{
|
|
|
53
54
|
|
|
54
55
|
// Title
|
|
55
56
|
if !title.isEmpty {
|
|
56
|
-
|
|
57
|
-
.font(.description1)
|
|
58
|
-
.ignoreBoldTextSetting()
|
|
57
|
+
MomoText(title, typography: .descriptionDefaultRegular)
|
|
59
58
|
}
|
|
60
59
|
}
|
|
61
60
|
}
|
|
62
61
|
|
|
63
62
|
private var borderColor: Color {
|
|
64
|
-
if disabled {
|
|
65
|
-
return
|
|
63
|
+
if disabled && checked {
|
|
64
|
+
return theme.colors.background.tonal
|
|
65
|
+
} else if disabled {
|
|
66
|
+
return theme.colors.border.disable
|
|
66
67
|
} else if checked {
|
|
67
|
-
return
|
|
68
|
+
return theme.colors.primary
|
|
68
69
|
} else {
|
|
69
|
-
return
|
|
70
|
+
return theme.colors.text.default
|
|
70
71
|
}
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
private var backgroundColor: Color {
|
|
74
75
|
if disabled && checked {
|
|
75
|
-
return
|
|
76
|
+
return theme.colors.background.tonal
|
|
76
77
|
} else if checked {
|
|
77
|
-
return
|
|
78
|
+
return theme.colors.primary
|
|
78
79
|
} else {
|
|
79
80
|
return Color.clear
|
|
80
81
|
}
|
package/ios/Chip/Chip.swift
CHANGED
|
@@ -2,17 +2,18 @@ import SwiftUI
|
|
|
2
2
|
import Foundation
|
|
3
3
|
|
|
4
4
|
public struct Chip: View {
|
|
5
|
+
@Environment(\.appTheme) private var theme
|
|
5
6
|
public enum ChipSize { case small, large }
|
|
6
7
|
|
|
7
8
|
public struct Dimensions {
|
|
9
|
+
let height: CGFloat
|
|
8
10
|
let horizontal: CGFloat
|
|
9
|
-
let vertical: CGFloat
|
|
10
11
|
let iconSize: CGFloat
|
|
11
12
|
let iconSpacing: CGFloat
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
public static let Large = Dimensions(
|
|
15
|
-
public static let Small = Dimensions(
|
|
15
|
+
public static let Large = Dimensions(height: 32, horizontal: 12, iconSize: 20, iconSpacing: 4)
|
|
16
|
+
public static let Small = Dimensions(height: 24, horizontal: 10, iconSize: 16, iconSpacing: 4)
|
|
16
17
|
|
|
17
18
|
private let label: String?
|
|
18
19
|
private let iconLeft: String?
|
|
@@ -53,14 +54,14 @@ public struct Chip: View {
|
|
|
53
54
|
let dims = (size == .small) ? Self.Small : Self.Large
|
|
54
55
|
|
|
55
56
|
let bg: Color = {
|
|
56
|
-
if selected { return
|
|
57
|
+
if selected { return theme.colors.background.selected }
|
|
57
58
|
if let explicit = backgroundColor { return explicit }
|
|
58
59
|
return Colors.black03
|
|
59
60
|
}()
|
|
60
61
|
|
|
61
|
-
let textColor: Color = selected ?
|
|
62
|
-
let leftTint: Color = selected ?
|
|
63
|
-
let rightTint: Color = selected ?
|
|
62
|
+
let textColor: Color = selected ? theme.colors.primary : theme.colors.text.default
|
|
63
|
+
let leftTint: Color = selected ? theme.colors.primary : iconLeftTint ?? theme.colors.text.default
|
|
64
|
+
let rightTint: Color = selected ? theme.colors.primary : iconRightTint ?? theme.colors.text.default
|
|
64
65
|
|
|
65
66
|
HStack(spacing: dims.iconSpacing) {
|
|
66
67
|
if let iconLeft {
|
|
@@ -77,7 +78,7 @@ public struct Chip: View {
|
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
80
|
.padding(.horizontal, dims.horizontal)
|
|
80
|
-
.
|
|
81
|
+
.frame(height: dims.height)
|
|
81
82
|
.background(
|
|
82
83
|
RoundedRectangle(cornerRadius: Radius.L, style: .continuous)
|
|
83
84
|
.fill(bg)
|
|
@@ -86,11 +87,24 @@ public struct Chip: View {
|
|
|
86
87
|
Group {
|
|
87
88
|
if selected {
|
|
88
89
|
RoundedRectangle(cornerRadius: Radius.L, style: .continuous)
|
|
89
|
-
.stroke(
|
|
90
|
+
.stroke(theme.colors.secondary, lineWidth: 2)
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
93
|
)
|
|
93
94
|
.contentShape(RoundedRectangle(cornerRadius: Radius.L, style: .continuous))
|
|
94
95
|
.onTapGesture(perform: onClick)
|
|
96
|
+
.modifier(ChipAccessibilityModifier(accessibilityLabel: accessibilityLabel))
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private struct ChipAccessibilityModifier: ViewModifier {
|
|
101
|
+
let accessibilityLabel: String?
|
|
102
|
+
|
|
103
|
+
func body(content: Content) -> some View {
|
|
104
|
+
if let id = accessibilityLabel {
|
|
105
|
+
content.accessibilityIdentifier(id)
|
|
106
|
+
} else {
|
|
107
|
+
content
|
|
108
|
+
}
|
|
95
109
|
}
|
|
96
110
|
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
|
|
3
|
+
public enum CollapseTitleSize {
|
|
4
|
+
case small
|
|
5
|
+
case medium
|
|
6
|
+
case large
|
|
7
|
+
|
|
8
|
+
var typography: TypographyStyle {
|
|
9
|
+
switch self {
|
|
10
|
+
case .small: return .headerSSemibold
|
|
11
|
+
case .medium: return .headerDefaultBold
|
|
12
|
+
case .large: return .headerMBold
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public struct Collapse<Content: View>: View {
|
|
18
|
+
@Environment(\.appTheme) private var theme
|
|
19
|
+
|
|
20
|
+
private let title: String
|
|
21
|
+
private let description: String?
|
|
22
|
+
private let image: String?
|
|
23
|
+
private let imageSize: CGFloat
|
|
24
|
+
private let subTitle: String?
|
|
25
|
+
private let tagLabel: String?
|
|
26
|
+
private let tagColor: Tag.TagColor
|
|
27
|
+
private let showBorder: Bool
|
|
28
|
+
private let expandDefault: Bool
|
|
29
|
+
private let titleSize: CollapseTitleSize
|
|
30
|
+
private let useBackgroundCollapseButton: Bool
|
|
31
|
+
private let backgroundColor: Color?
|
|
32
|
+
private let titleColor: Color?
|
|
33
|
+
private let onPress: ((Bool) -> Void)?
|
|
34
|
+
private let content: (() -> Content)?
|
|
35
|
+
|
|
36
|
+
@State private var expanded: Bool
|
|
37
|
+
|
|
38
|
+
public init(
|
|
39
|
+
title: String,
|
|
40
|
+
description: String? = nil,
|
|
41
|
+
image: String? = nil,
|
|
42
|
+
imageSize: CGFloat = 24,
|
|
43
|
+
subTitle: String? = nil,
|
|
44
|
+
tagLabel: String? = nil,
|
|
45
|
+
tagColor: Tag.TagColor = .default,
|
|
46
|
+
showBorder: Bool = false,
|
|
47
|
+
expandDefault: Bool = false,
|
|
48
|
+
titleSize: CollapseTitleSize = .medium,
|
|
49
|
+
useBackgroundCollapseButton: Bool = false,
|
|
50
|
+
backgroundColor: Color? = nil,
|
|
51
|
+
titleColor: Color? = nil,
|
|
52
|
+
onPress: ((Bool) -> Void)? = nil,
|
|
53
|
+
@ViewBuilder content: @escaping () -> Content
|
|
54
|
+
) {
|
|
55
|
+
self.title = title
|
|
56
|
+
self.description = description
|
|
57
|
+
self.image = image
|
|
58
|
+
self.imageSize = imageSize
|
|
59
|
+
self.subTitle = subTitle
|
|
60
|
+
self.tagLabel = tagLabel
|
|
61
|
+
self.tagColor = tagColor
|
|
62
|
+
self.showBorder = showBorder
|
|
63
|
+
self.expandDefault = expandDefault
|
|
64
|
+
self.titleSize = titleSize
|
|
65
|
+
self.useBackgroundCollapseButton = useBackgroundCollapseButton
|
|
66
|
+
self.backgroundColor = backgroundColor
|
|
67
|
+
self.titleColor = titleColor
|
|
68
|
+
self.onPress = onPress
|
|
69
|
+
self.content = content
|
|
70
|
+
_expanded = State(initialValue: expandDefault)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private var resolvedBackgroundColor: Color {
|
|
74
|
+
backgroundColor ?? theme.colors.background.surface
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public var body: some View {
|
|
78
|
+
VStack(spacing: 0) {
|
|
79
|
+
header
|
|
80
|
+
|
|
81
|
+
if let content {
|
|
82
|
+
if expanded {
|
|
83
|
+
VStack(spacing: 0) {
|
|
84
|
+
content()
|
|
85
|
+
}
|
|
86
|
+
.frame(maxWidth: .infinity)
|
|
87
|
+
.overlay(
|
|
88
|
+
showBorder
|
|
89
|
+
? RoundedRectangle(cornerRadius: 0)
|
|
90
|
+
.stroke(theme.colors.border.default, lineWidth: 1)
|
|
91
|
+
: nil
|
|
92
|
+
)
|
|
93
|
+
.transition(.move(edge: .top).combined(with: .opacity))
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
.frame(maxWidth: .infinity)
|
|
98
|
+
.background(resolvedBackgroundColor)
|
|
99
|
+
.clipShape(RoundedRectangle(cornerRadius: Radius.S, style: .continuous))
|
|
100
|
+
.overlay(
|
|
101
|
+
showBorder
|
|
102
|
+
? RoundedRectangle(cornerRadius: Radius.S, style: .continuous)
|
|
103
|
+
.stroke(theme.colors.border.default, lineWidth: 1)
|
|
104
|
+
: nil
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private var header: some View {
|
|
109
|
+
SwiftUI.Button(action: {
|
|
110
|
+
onPress?(expanded)
|
|
111
|
+
withAnimation(.easeInOut(duration: 0.3)) {
|
|
112
|
+
expanded.toggle()
|
|
113
|
+
}
|
|
114
|
+
}) {
|
|
115
|
+
HStack(alignment: .top, spacing: 0) {
|
|
116
|
+
if let image {
|
|
117
|
+
ImageView(image, contentMode: .fill)
|
|
118
|
+
.frame(width: imageSize, height: imageSize)
|
|
119
|
+
.clipShape(RoundedRectangle(cornerRadius: Radius.XS, style: .continuous))
|
|
120
|
+
Spacer().frame(width: Spacing.S)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
VStack(alignment: .leading, spacing: 0) {
|
|
124
|
+
MomoText(
|
|
125
|
+
title,
|
|
126
|
+
typography: titleSize.typography,
|
|
127
|
+
color: titleColor ?? theme.colors.text.default
|
|
128
|
+
)
|
|
129
|
+
if let description {
|
|
130
|
+
MomoText(
|
|
131
|
+
description,
|
|
132
|
+
typography: .bodyDefaultRegular,
|
|
133
|
+
color: theme.colors.text.secondary
|
|
134
|
+
)
|
|
135
|
+
.lineLimit(2)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
.frame(maxWidth: .infinity, alignment: .leading)
|
|
139
|
+
|
|
140
|
+
if subTitle != nil || tagLabel != nil {
|
|
141
|
+
Spacer().frame(width: Spacing.S)
|
|
142
|
+
if let subTitle {
|
|
143
|
+
MomoText(
|
|
144
|
+
subTitle,
|
|
145
|
+
typography: .bodyDefaultRegular,
|
|
146
|
+
color: theme.colors.text.secondary
|
|
147
|
+
)
|
|
148
|
+
.lineLimit(1)
|
|
149
|
+
} else if let tagLabel {
|
|
150
|
+
Tag(label: tagLabel, color: tagColor)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
Spacer().frame(width: Spacing.S)
|
|
155
|
+
chevron
|
|
156
|
+
}
|
|
157
|
+
.padding(.horizontal, Spacing.M)
|
|
158
|
+
.padding(.vertical, Spacing.S)
|
|
159
|
+
.frame(maxWidth: .infinity)
|
|
160
|
+
.contentShape(Rectangle())
|
|
161
|
+
}
|
|
162
|
+
.buttonStyle(.plain)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
private var chevron: some View {
|
|
166
|
+
Group {
|
|
167
|
+
if useBackgroundCollapseButton {
|
|
168
|
+
Icon(source: "arrow_chevron_down_small", size: 16, color: theme.colors.primary)
|
|
169
|
+
.rotationEffect(.degrees(expanded ? 180 : 0))
|
|
170
|
+
.frame(width: 24, height: 24)
|
|
171
|
+
.background(
|
|
172
|
+
RoundedRectangle(cornerRadius: Radius.M, style: .continuous)
|
|
173
|
+
.fill(theme.colors.background.tonal)
|
|
174
|
+
)
|
|
175
|
+
} else {
|
|
176
|
+
Icon(source: "arrow_chevron_down_small", size: 24, color: theme.colors.text.default)
|
|
177
|
+
.rotationEffect(.degrees(expanded ? 180 : 0))
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
.animation(.easeInOut(duration: 0.3), value: expanded)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
@@ -3,18 +3,18 @@ import Foundation
|
|
|
3
3
|
import SwiftUI
|
|
4
4
|
|
|
5
5
|
public enum Colors {
|
|
6
|
-
public static let primary = Color("Primary")
|
|
7
|
-
public static let primaryDark = Color("PrimaryDark")
|
|
8
|
-
public static let primaryLight = Color("PrimaryLight")
|
|
9
|
-
public static let secondary = Color("Secondary")
|
|
10
|
-
public static let background = Color("Background")
|
|
11
|
-
public static let border = Color("Border")
|
|
12
|
-
public static let text = Color("
|
|
13
|
-
public static let textSecondary = Color("TextSecondary")
|
|
14
|
-
public static let card = Color("Card")
|
|
15
|
-
public static let error = Color("Error")
|
|
16
|
-
public static let info = Color("
|
|
17
|
-
public static let success = Color("Success")
|
|
6
|
+
public static let primary = Color.momoAsset("Primary")
|
|
7
|
+
public static let primaryDark = Color.momoAsset("PrimaryDark")
|
|
8
|
+
public static let primaryLight = Color.momoAsset("PrimaryLight")
|
|
9
|
+
public static let secondary = Color.momoAsset("Secondary")
|
|
10
|
+
public static let background = Color.momoAsset("Background")
|
|
11
|
+
public static let border = Color.momoAsset("Border")
|
|
12
|
+
public static let text = Color.momoAsset("ThemeColors/text-default")
|
|
13
|
+
public static let textSecondary = Color.momoAsset("TextSecondary")
|
|
14
|
+
public static let card = Color.momoAsset("Card")
|
|
15
|
+
public static let error = Color.momoAsset("Error")
|
|
16
|
+
public static let info = Color(hex: "007aff")
|
|
17
|
+
public static let success = Color.momoAsset("Success")
|
|
18
18
|
|
|
19
19
|
public static let black20 = Color(hex: "000000")
|
|
20
20
|
public static let black19 = Color(hex: "18191a")
|