@momo-kits/native-kits 0.167.1-duo.3-debug → 0.167.1-duo.4
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 +17 -8
- package/ios/Application/ApplicationEnvironment.swift +6 -0
- package/ios/Application/Components.swift +1 -3
- package/ios/Application/HeaderRight.swift +19 -27
- package/ios/Application/Navigation/BottomTab/BottomTab.swift +9 -30
- package/ios/Application/Navigation/BottomTab/BottomTabBar.swift +2 -5
- package/ios/Application/Navigation/HeaderUser.swift +1 -7
- package/ios/Application/Navigation/NavigationContainer.swift +45 -45
- package/ios/Application/Navigation/Navigator.swift +122 -29
- package/ios/Application/Navigation/NavigatorManager.swift +13 -6
- package/ios/Application/Navigation/Overplay/BottomSheet.swift +4 -41
- package/ios/Application/Navigation/Overplay/ModalScreen.swift +1 -5
- package/ios/Application/Navigation/component/Header.swift +4 -12
- package/ios/Application/Navigation/component/HeaderBackground.swift +2 -3
- package/ios/Application/Navigation/component/NavigationFooter.swift +1 -1
- package/ios/Application/Navigation/component/NavigationHeaderRight.swift +9 -61
- package/ios/Application/StackScreen.swift +18 -135
- package/ios/CalculatorKeyboard/CalculatorKeyboard.swift +59 -5
- package/ios/Colors+Radius+Spacing/Colors.swift +1 -1
- package/ios/Extensions/Color++.swift +20 -9
- package/ios/Extensions/OptionalEnvironmentObject.swift +12 -0
- package/ios/Icon/Icon.swift +14 -22
- package/ios/Icon/Icons.swift +1329 -0
- package/ios/Image/Image.swift +16 -5
- package/ios/Lottie/LottieView.swift +4 -2
- package/ios/Popup/PopupDisplay.swift +68 -84
- package/ios/Popup/PopupNotify.swift +32 -43
- package/ios/Popup/PopupPromotion.swift +6 -18
- package/ios/Resources/dot_loading.json +558 -0
- package/ios/Resources/lottie_circle_loader.json +1 -0
- package/ios/Template/TrustBanner/TrustBanner.swift +69 -31
- package/ios/native-kits.podspec +1 -1
- package/ios-demo/MoMoUIKitsDemo.podspec +1 -1
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +0 -1
- package/package.json +1 -1
- package/scripts/gen-ios-icons.mjs +36 -0
- package/.claude/scheduled_tasks.lock +0 -1
- package/.claude/settings.local.json +0 -185
- package/build.gradle.kts +0 -11
- package/compose/build.gradle.kts +0 -204
- package/compose/build.gradle.kts.backup +0 -204
- package/compose/compose.podspec +0 -47
- package/compose/src/androidMain/kotlin/vn/momo/kits/const/HostFont.android.kt +0 -19
- package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +0 -6
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/BackGesture.android.kt +0 -12
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +0 -7
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +0 -153
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +0 -52
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +0 -124
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +0 -183
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +0 -207
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +0 -39
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +0 -86
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +0 -76
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +0 -76
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +0 -293
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +0 -33
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +0 -831
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +0 -269
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +0 -110
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +0 -378
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +0 -56
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +0 -69
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +0 -157
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +0 -82
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +0 -32
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +0 -338
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +0 -175
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +0 -356
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +0 -113
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -89
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +0 -128
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +0 -209
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +0 -542
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +0 -49
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +0 -76
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +0 -125
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +0 -231
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +0 -189
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +0 -475
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +0 -114
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +0 -266
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +0 -240
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +0 -223
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +0 -264
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +0 -185
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +0 -343
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +0 -108
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +0 -56
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +0 -41
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +0 -84
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +0 -40
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +0 -361
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +0 -108
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +0 -310
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +0 -59
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +0 -87
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +0 -21
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +0 -90
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +0 -323
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +0 -220
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +0 -473
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +0 -122
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +0 -199
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +0 -91
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +0 -552
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +0 -88
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +0 -125
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +0 -207
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +0 -498
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +0 -176
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +0 -182
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +0 -193
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +0 -29
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +0 -234
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +0 -188
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +0 -325
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/HostFont.kt +0 -16
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitDesignSystem.kt +0 -18
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitFontScale.kt +0 -22
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +0 -12
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +0 -16
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +0 -188
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +0 -297
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +0 -54
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +0 -50
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/ScreenLayout.kt +0 -187
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +0 -41
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -52
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +0 -66
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +0 -11
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +0 -104
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +0 -48
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +0 -51
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +0 -338
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/HostBackGestureBridge.kt +0 -58
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +0 -137
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +0 -106
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +0 -205
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +0 -393
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +0 -8
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +0 -648
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackTransition.kt +0 -148
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/SwipeBackHaptic.kt +0 -35
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +0 -194
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +0 -232
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +0 -86
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoTabBar.kt +0 -281
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +0 -169
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +0 -408
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +0 -108
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderJourney.kt +0 -105
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderLocation.kt +0 -74
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +0 -354
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +0 -37
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +0 -363
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SideBar.kt +0 -169
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +0 -132
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +0 -127
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/BackGesture.kt +0 -12
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +0 -91
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +0 -9
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +0 -74
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +0 -1329
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +0 -55
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +0 -15
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +0 -118
- package/compose/src/iosMain/kotlin/vn/momo/kits/const/HostFont.ios.kt +0 -40
- package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/HostBackGesture.ios.kt +0 -45
- package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +0 -32
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/BackGesture.ios.kt +0 -38
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +0 -66
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +0 -217
- package/gradle/libs.versions.toml +0 -69
- package/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/gradle/wrapper/gradle-wrapper.properties +0 -8
- package/gradle.properties +0 -26
- package/gradlew +0 -252
- package/gradlew.bat +0 -94
- package/ios/Application/Layout/ScreenLayout.swift +0 -196
- package/ios/Application/Navigation/BottomTab/DuoTabBar.swift +0 -275
- package/ios/Application/Navigation/component/DuoScrollGradient.swift +0 -55
- package/ios/Application/Navigation/component/SideBar.swift +0 -155
- package/ios/Popup/PopupLayout.swift +0 -45
- package/ios-demo/README.md +0 -120
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DuoTabDemo.swift +0 -76
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IPhoneDuoDemo.swift +0 -170
- package/local.properties +0 -8
- package/settings.gradle.kts +0 -64
|
@@ -1,275 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// DuoTabBar.swift
|
|
3
|
-
// MoMoUIKits
|
|
4
|
-
//
|
|
5
|
-
// iPhone Duo tab bar, port of RN `BottomTab/DuoTabBar.tsx` (Figma Fold-Design-System MT1/MT2):
|
|
6
|
-
// a glass rail in the side bar, or a floating glass bar when unfolded portrait.
|
|
7
|
-
//
|
|
8
|
-
|
|
9
|
-
import SwiftUI
|
|
10
|
-
|
|
11
|
-
private let itemSize = DuoMetrics.controlSize
|
|
12
|
-
private let iconSize: CGFloat = 28
|
|
13
|
-
private let qrIconSize: CGFloat = 24
|
|
14
|
-
private let railPadding: CGFloat = 6
|
|
15
|
-
private let railGap = Spacing.XXS
|
|
16
|
-
// selection bubble overflows the 48 rail cell by 5 above and below (Figma MT2)
|
|
17
|
-
private let railBubbleWidth: CGFloat = 44
|
|
18
|
-
private let railBubbleHeight: CGFloat = 58
|
|
19
|
-
let duoFloatingTabBarHeight: CGFloat = 62
|
|
20
|
-
private let floatingPadding = Spacing.XS
|
|
21
|
-
private let floatingQrSize: CGFloat = 44
|
|
22
|
-
// floating bar spans 6 of the 8 portrait grid columns, like the content
|
|
23
|
-
private let gridColumns: CGFloat = 8
|
|
24
|
-
private let gridSpan: CGFloat = 6
|
|
25
|
-
private let tabSpring = Animation.interpolatingSpring(mass: 0.8, stiffness: 220, damping: 18)
|
|
26
|
-
|
|
27
|
-
/// Room tab screens leave for the Duo tab bar, provided by BottomTab to its tab StackScreens.
|
|
28
|
-
struct DuoTabBarInsets: Equatable {
|
|
29
|
-
/// Floating bar overlays the content: scroll content, footer and FAB keep clear of it.
|
|
30
|
-
var overlay: CGFloat = 0
|
|
31
|
-
/// Rail sits at the bottom of the side strip: the header side bar stays above it.
|
|
32
|
-
var sideBarReserve: CGFloat = 0
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
private struct DuoTabBarInsetsKey: EnvironmentKey {
|
|
36
|
-
static let defaultValue = DuoTabBarInsets()
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
extension EnvironmentValues {
|
|
40
|
-
var duoTabBarInsets: DuoTabBarInsets {
|
|
41
|
-
get { self[DuoTabBarInsetsKey.self] }
|
|
42
|
-
set { self[DuoTabBarInsetsKey.self] = newValue }
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
extension ScreenLayout {
|
|
47
|
-
func duoTabBarInsets(itemCount: Int, hasFloatingButton: Bool) -> DuoTabBarInsets {
|
|
48
|
-
guard isIPhoneDuo else { return DuoTabBarInsets() }
|
|
49
|
-
guard sideBar != nil else {
|
|
50
|
-
return DuoTabBarInsets(overlay: duoFloatingTabBarHeight + Spacing.M)
|
|
51
|
-
}
|
|
52
|
-
let count = CGFloat(itemCount)
|
|
53
|
-
let rail = railPadding * 2 + count * itemSize + max(count - 1, 0) * railGap
|
|
54
|
-
let qr = hasFloatingButton ? Spacing.M + itemSize : 0
|
|
55
|
-
return DuoTabBarInsets(sideBarReserve: rail + qr + Spacing.XL)
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/// Glass on iOS 26, a system blur before it (RN GlassView's fallback).
|
|
60
|
-
struct DuoBarMaterial<S: Shape>: ViewModifier {
|
|
61
|
-
let shape: S
|
|
62
|
-
var visible: Bool = true
|
|
63
|
-
|
|
64
|
-
func body(content: Content) -> some View {
|
|
65
|
-
content.background(material.allowsHitTesting(false))
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
@ViewBuilder
|
|
69
|
-
private var material: some View {
|
|
70
|
-
#if compiler(>=6.2)
|
|
71
|
-
if #available(iOS 26.0, *) {
|
|
72
|
-
// glass materializes by toggling its effect, it does not fade with opacity
|
|
73
|
-
Color.clear
|
|
74
|
-
.glassEffect(visible ? .regular : .identity, in: shape)
|
|
75
|
-
.shadow(color: Color.black.opacity(visible ? 0.16 : 0), radius: 16, x: 0, y: 6)
|
|
76
|
-
.animation(.easeInOut(duration: 0.25), value: visible)
|
|
77
|
-
} else {
|
|
78
|
-
blur
|
|
79
|
-
}
|
|
80
|
-
#else
|
|
81
|
-
blur
|
|
82
|
-
#endif
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
private var blur: some View {
|
|
86
|
-
shape.fill(.regularMaterial)
|
|
87
|
-
.shadow(color: Color.black.opacity(0.16), radius: 16, x: 0, y: 6)
|
|
88
|
-
.opacity(visible ? 1 : 0)
|
|
89
|
-
.animation(.easeInOut(duration: 0.25), value: visible)
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
struct DuoTabBar: View {
|
|
94
|
-
let items: [BottomTabItem]
|
|
95
|
-
let floatingButton: BottomTabFloatingButton?
|
|
96
|
-
let selectedIndex: Int
|
|
97
|
-
let onTabSelected: (Int) -> Void
|
|
98
|
-
|
|
99
|
-
@Environment(\.screenLayout) private var layout
|
|
100
|
-
|
|
101
|
-
var body: some View {
|
|
102
|
-
if let sideBar = layout.sideBar {
|
|
103
|
-
DuoRailTabBar(sideBar: sideBar, items: items, floatingButton: floatingButton,
|
|
104
|
-
selectedIndex: selectedIndex, onTabSelected: onTabSelected)
|
|
105
|
-
} else {
|
|
106
|
-
DuoFloatingTabBar(items: items, floatingButton: floatingButton,
|
|
107
|
-
selectedIndex: selectedIndex, onTabSelected: onTabSelected)
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/// Vertical bar anchored to the bottom of the side bar, QR button below it (Figma MT1-C/E).
|
|
113
|
-
private struct DuoRailTabBar: View {
|
|
114
|
-
let sideBar: SideBarLayout
|
|
115
|
-
let items: [BottomTabItem]
|
|
116
|
-
let floatingButton: BottomTabFloatingButton?
|
|
117
|
-
let selectedIndex: Int
|
|
118
|
-
let onTabSelected: (Int) -> Void
|
|
119
|
-
|
|
120
|
-
@Environment(\.appTheme) private var theme
|
|
121
|
-
|
|
122
|
-
private var isRight: Bool { sideBar.edge == .right }
|
|
123
|
-
|
|
124
|
-
var body: some View {
|
|
125
|
-
VStack(spacing: Spacing.M) {
|
|
126
|
-
ZStack(alignment: .top) {
|
|
127
|
-
Capsule()
|
|
128
|
-
.fill(theme.colors.background.selected)
|
|
129
|
-
.frame(width: railBubbleWidth, height: railBubbleHeight)
|
|
130
|
-
.offset(y: railPadding - (railBubbleHeight - itemSize) / 2
|
|
131
|
-
+ CGFloat(selectedIndex) * (itemSize + railGap))
|
|
132
|
-
.animation(tabSpring, value: selectedIndex)
|
|
133
|
-
|
|
134
|
-
VStack(spacing: railGap) {
|
|
135
|
-
ForEach(items.indices, id: \.self) { index in
|
|
136
|
-
SwiftUI.Button { onTabSelected(index) } label: {
|
|
137
|
-
DuoTabIcon(item: items[index], selected: index == selectedIndex)
|
|
138
|
-
.frame(width: itemSize, height: itemSize)
|
|
139
|
-
.contentShape(Rectangle())
|
|
140
|
-
}
|
|
141
|
-
.buttonStyle(.plain)
|
|
142
|
-
.accessibilityLabel(items[index].label)
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
.padding(.vertical, railPadding)
|
|
146
|
-
}
|
|
147
|
-
.frame(width: itemSize)
|
|
148
|
-
.modifier(DuoBarMaterial(shape: RoundedRectangle(cornerRadius: Radius.XL)))
|
|
149
|
-
.accessibilityIdentifier("bottom_tab_bar")
|
|
150
|
-
|
|
151
|
-
if let floatingButton {
|
|
152
|
-
DuoQrButton(data: floatingButton, size: itemSize)
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
.padding(isRight ? .leading : .trailing, Spacing.M)
|
|
156
|
-
.frame(width: sideBar.width, alignment: isRight ? .leading : .trailing)
|
|
157
|
-
.padding(.bottom, Spacing.XL)
|
|
158
|
-
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: isRight ? .bottomTrailing : .bottomLeading)
|
|
159
|
-
.ignoresSafeArea()
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/// Floating labelled bar for the unfolded portrait display, QR in the middle cell (Figma MT1-M).
|
|
164
|
-
private struct DuoFloatingTabBar: View {
|
|
165
|
-
let items: [BottomTabItem]
|
|
166
|
-
let floatingButton: BottomTabFloatingButton?
|
|
167
|
-
let selectedIndex: Int
|
|
168
|
-
let onTabSelected: (Int) -> Void
|
|
169
|
-
|
|
170
|
-
@Environment(\.screenLayout) private var layout
|
|
171
|
-
@Environment(\.appTheme) private var theme
|
|
172
|
-
|
|
173
|
-
private var barWidth: CGFloat {
|
|
174
|
-
let columnWidth = (layout.width - 2 * Spacing.M - (gridColumns - 1) * Spacing.M) / gridColumns
|
|
175
|
-
return columnWidth * gridSpan + (gridSpan - 1) * Spacing.M
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
private var useQr: Bool { floatingButton != nil && items.count % 2 == 0 }
|
|
179
|
-
private var middle: Int { items.count / 2 }
|
|
180
|
-
private var cellCount: Int { items.count + (useQr ? 1 : 0) }
|
|
181
|
-
private var cellWidth: CGFloat { (barWidth - floatingPadding * 2) / CGFloat(max(cellCount, 1)) }
|
|
182
|
-
private var visualIndex: Int { useQr && selectedIndex >= middle ? selectedIndex + 1 : selectedIndex }
|
|
183
|
-
|
|
184
|
-
var body: some View {
|
|
185
|
-
ZStack(alignment: .leading) {
|
|
186
|
-
Capsule()
|
|
187
|
-
.fill(theme.colors.background.selected)
|
|
188
|
-
.frame(width: cellWidth)
|
|
189
|
-
.offset(x: CGFloat(visualIndex) * cellWidth)
|
|
190
|
-
.animation(tabSpring, value: visualIndex)
|
|
191
|
-
|
|
192
|
-
HStack(spacing: 0) {
|
|
193
|
-
ForEach(0..<cellCount, id: \.self) { cell in
|
|
194
|
-
if useQr && cell == middle, let floatingButton {
|
|
195
|
-
DuoQrButton(data: floatingButton, size: floatingQrSize)
|
|
196
|
-
.frame(width: cellWidth)
|
|
197
|
-
} else {
|
|
198
|
-
let index = useQr && cell > middle ? cell - 1 : cell
|
|
199
|
-
tabCell(index)
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
.padding(floatingPadding)
|
|
205
|
-
.frame(width: barWidth, height: duoFloatingTabBarHeight)
|
|
206
|
-
.modifier(DuoBarMaterial(shape: Capsule()))
|
|
207
|
-
.accessibilityIdentifier("bottom_tab_bar")
|
|
208
|
-
.padding(.bottom, layout.insets.bottom + Spacing.M)
|
|
209
|
-
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom)
|
|
210
|
-
.ignoresSafeArea()
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
private func tabCell(_ index: Int) -> some View {
|
|
214
|
-
let selected = index == selectedIndex
|
|
215
|
-
return SwiftUI.Button { onTabSelected(index) } label: {
|
|
216
|
-
VStack(spacing: Spacing.XXS) {
|
|
217
|
-
DuoTabIcon(item: items[index], selected: selected)
|
|
218
|
-
MomoText(
|
|
219
|
-
items[index].label,
|
|
220
|
-
typography: .labelXsMedium,
|
|
221
|
-
color: selected ? theme.colors.primary : theme.colors.text.default,
|
|
222
|
-
textAlign: .center,
|
|
223
|
-
maxLines: 1
|
|
224
|
-
)
|
|
225
|
-
}
|
|
226
|
-
.frame(width: cellWidth)
|
|
227
|
-
.frame(maxHeight: .infinity)
|
|
228
|
-
.contentShape(Rectangle())
|
|
229
|
-
}
|
|
230
|
-
.buttonStyle(.plain)
|
|
231
|
-
.accessibilityLabel(items[index].label)
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
private struct DuoTabIcon: View {
|
|
236
|
-
let item: BottomTabItem
|
|
237
|
-
let selected: Bool
|
|
238
|
-
|
|
239
|
-
@Environment(\.appTheme) private var theme
|
|
240
|
-
|
|
241
|
-
private var badgeLabel: String? {
|
|
242
|
-
guard let label = item.badgeLabel else { return nil }
|
|
243
|
-
if let n = Int(label), n == 0 { return nil }
|
|
244
|
-
return label
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
var body: some View {
|
|
248
|
-
Icon(source: item.icon, size: iconSize, color: selected ? theme.colors.primary : theme.colors.text.default)
|
|
249
|
-
.overlay(alignment: .topTrailing) {
|
|
250
|
-
if let badgeLabel, !badgeLabel.isEmpty {
|
|
251
|
-
Badge(label: badgeLabel).offset(x: Spacing.S, y: -Spacing.XS)
|
|
252
|
-
} else if badgeLabel != nil || item.showDot {
|
|
253
|
-
BadgeDot(size: .small)
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
private struct DuoQrButton: View {
|
|
260
|
-
let data: BottomTabFloatingButton
|
|
261
|
-
let size: CGFloat
|
|
262
|
-
|
|
263
|
-
@Environment(\.appTheme) private var theme
|
|
264
|
-
|
|
265
|
-
var body: some View {
|
|
266
|
-
SwiftUI.Button(action: data.onPress) {
|
|
267
|
-
Circle()
|
|
268
|
-
.fill(theme.colors.primary)
|
|
269
|
-
.frame(width: size, height: size)
|
|
270
|
-
.overlay(Icon(source: data.icon, size: qrIconSize, color: Colors.black01))
|
|
271
|
-
}
|
|
272
|
-
.buttonStyle(.plain)
|
|
273
|
-
.accessibilityLabel(data.label)
|
|
274
|
-
}
|
|
275
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// DuoScrollGradient.swift
|
|
3
|
-
// MoMoUIKits
|
|
4
|
-
//
|
|
5
|
-
// Port of RN `DuoScrollGradient` (Components/DuoGlassBackground.tsx): with the iPhone Duo
|
|
6
|
-
// glass header the content scrolls under the bar, so the header gradient is drawn under it.
|
|
7
|
-
//
|
|
8
|
-
|
|
9
|
-
import SwiftUI
|
|
10
|
-
|
|
11
|
-
// extended headers run their gradient this far below the header, as off Duo
|
|
12
|
-
private let extendedGradientExtra: CGFloat = 52
|
|
13
|
-
// scroll distance over which the extended gradient collapses to the header
|
|
14
|
-
private let extendedCollapseDistance: CGFloat = 100
|
|
15
|
-
|
|
16
|
-
struct DuoScrollGradient: View {
|
|
17
|
-
let scrollOffset: CGFloat
|
|
18
|
-
let headerHeight: CGFloat
|
|
19
|
-
let extended: Bool
|
|
20
|
-
|
|
21
|
-
@Environment(\.appTheme) private var theme
|
|
22
|
-
@Environment(\.screenLayout) private var layout
|
|
23
|
-
|
|
24
|
-
private var scroll: CGFloat { max(scrollOffset, 0) }
|
|
25
|
-
|
|
26
|
-
private var gradient: LinearGradient {
|
|
27
|
-
LinearGradient(
|
|
28
|
-
colors: [theme.colors.gradient, theme.colors.gradient.opacity(0)],
|
|
29
|
-
startPoint: .top,
|
|
30
|
-
endPoint: .bottom
|
|
31
|
-
)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
var body: some View {
|
|
35
|
-
Group {
|
|
36
|
-
if extended {
|
|
37
|
-
// extended squeezes the whole fade into its box and fades out
|
|
38
|
-
let progress = min(scroll / extendedCollapseDistance, 1)
|
|
39
|
-
gradient
|
|
40
|
-
.frame(height: headerHeight + extendedGradientExtra * (1 - progress))
|
|
41
|
-
.opacity(1 - min(scroll / extendedGradientExtra, 1))
|
|
42
|
-
} else {
|
|
43
|
-
// default keeps the off-Duo 375:154 shape, the header clips it, and scrolls away
|
|
44
|
-
gradient
|
|
45
|
-
.frame(height: layout.width * 154 / 375)
|
|
46
|
-
.frame(height: headerHeight, alignment: .top)
|
|
47
|
-
.clipped()
|
|
48
|
-
.offset(y: -scroll)
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
|
|
52
|
-
.ignoresSafeArea()
|
|
53
|
-
.allowsHitTesting(false)
|
|
54
|
-
}
|
|
55
|
-
}
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// SideBar.swift
|
|
3
|
-
// MoMoUIKits
|
|
4
|
-
//
|
|
5
|
-
// iPhone Duo: back and toolkit leave the header bar for a column in the side safe area,
|
|
6
|
-
// as the system bars do. Port of RN `SideBarButton.tsx` + `useSideBarItemStyle`.
|
|
7
|
-
//
|
|
8
|
-
|
|
9
|
-
import SwiftUI
|
|
10
|
-
|
|
11
|
-
private let sideBarIconSize: CGFloat = 24
|
|
12
|
-
|
|
13
|
-
/// Toolkit data when `headerRight` renders the kit toolkit; nil for a custom header right.
|
|
14
|
-
func toolkitHeaderRight(_ headerRight: (() -> any View)?) -> (data: HeaderRightData?, tintColor: Color?)? {
|
|
15
|
-
guard let view = headerRight?() else { return nil }
|
|
16
|
-
if let toolkit = view as? HeaderRight { return (toolkit.headerRight, toolkit.tintColor) }
|
|
17
|
-
if let toolkit = view as? NavigationHeaderRight { return (toolkit.headerRight, toolkit.tintColor) }
|
|
18
|
-
return nil
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/// The back button and toolkit column, placed in window coordinates over the side strip.
|
|
22
|
-
struct HeaderSideBar: View {
|
|
23
|
-
let sideBar: SideBarLayout
|
|
24
|
-
let goBack: (() -> Void)?
|
|
25
|
-
let toolkit: (data: HeaderRightData?, tintColor: Color?)?
|
|
26
|
-
let headerColor: HeaderColor
|
|
27
|
-
/// What footer / tab bar / home indicator take from the bottom; the column stays above it.
|
|
28
|
-
let bottomInset: CGFloat
|
|
29
|
-
|
|
30
|
-
@Environment(\.screenLayout) private var layout
|
|
31
|
-
@State private var columnHeight: CGFloat = 0
|
|
32
|
-
|
|
33
|
-
private var isRight: Bool { sideBar.edge == .right }
|
|
34
|
-
|
|
35
|
-
private var top: CGFloat {
|
|
36
|
-
let maxY = layout.height - bottomInset - Spacing.XL - columnHeight
|
|
37
|
-
return max(min(sideBar.top, maxY), 0)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
var body: some View {
|
|
41
|
-
VStack(alignment: isRight ? .leading : .trailing, spacing: Spacing.M) {
|
|
42
|
-
if let goBack {
|
|
43
|
-
SideBarButton(
|
|
44
|
-
icon: "arrow-back",
|
|
45
|
-
tintColor: headerColor.tintIconColor,
|
|
46
|
-
accessibilityId: "btn_navigation_back",
|
|
47
|
-
action: goBack
|
|
48
|
-
)
|
|
49
|
-
} else {
|
|
50
|
-
// keep the slot so the toolkit does not jump between root and pushed screens
|
|
51
|
-
Color.clear.frame(width: DuoMetrics.controlSize, height: DuoMetrics.controlSize)
|
|
52
|
-
}
|
|
53
|
-
if let toolkit {
|
|
54
|
-
ToolkitNavigationHeaderRight(
|
|
55
|
-
headerRight: toolkit.data,
|
|
56
|
-
tintColor: toolkit.tintColor ?? headerColor.tintIconColor,
|
|
57
|
-
vertical: true
|
|
58
|
-
)
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
.padding(isRight ? .leading : .trailing, Spacing.M)
|
|
62
|
-
.frame(width: sideBar.width, alignment: isRight ? .leading : .trailing)
|
|
63
|
-
.background(
|
|
64
|
-
GeometryReader { proxy in
|
|
65
|
-
Color.clear
|
|
66
|
-
.onAppear { columnHeight = proxy.size.height }
|
|
67
|
-
.onChange(of: proxy.size.height) { columnHeight = $0 }
|
|
68
|
-
}
|
|
69
|
-
)
|
|
70
|
-
.padding(.top, top)
|
|
71
|
-
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: isRight ? .topTrailing : .topLeading)
|
|
72
|
-
.ignoresSafeArea()
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/// Dark glass under light icons (banner headers), light glass otherwise.
|
|
77
|
-
private struct SideBarGlass<S: Shape>: ViewModifier {
|
|
78
|
-
let tintColor: Color?
|
|
79
|
-
let shape: S
|
|
80
|
-
|
|
81
|
-
private var isDark: Bool { tintColor == Colors.black01 || tintColor == .white }
|
|
82
|
-
|
|
83
|
-
func body(content: Content) -> some View {
|
|
84
|
-
if isDark {
|
|
85
|
-
content
|
|
86
|
-
.background(shape.fill(Colors.black20.opacity(0.5)))
|
|
87
|
-
.overlay(shape.stroke(Colors.black01.opacity(0.2), lineWidth: 0.5))
|
|
88
|
-
} else {
|
|
89
|
-
content
|
|
90
|
-
.background(
|
|
91
|
-
shape.fill(Colors.black01.opacity(0.85))
|
|
92
|
-
.shadow(color: Color.black.opacity(0.12), radius: 4, x: 0, y: 2)
|
|
93
|
-
)
|
|
94
|
-
.overlay(shape.stroke(Colors.black20.opacity(0.08), lineWidth: 0.5))
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/// 48pt glass circle for a single side bar control.
|
|
100
|
-
struct SideBarButton: View {
|
|
101
|
-
let icon: String
|
|
102
|
-
var tintColor: Color?
|
|
103
|
-
var showBadge: Bool = false
|
|
104
|
-
var disabled: Bool = false
|
|
105
|
-
var accessibilityId: String?
|
|
106
|
-
let action: () -> Void
|
|
107
|
-
|
|
108
|
-
var body: some View {
|
|
109
|
-
SwiftUI.Button(action: { if !disabled { action() } }) {
|
|
110
|
-
Icon(source: icon, size: sideBarIconSize, color: tintColor ?? Colors.black17)
|
|
111
|
-
.frame(width: DuoMetrics.controlSize, height: DuoMetrics.controlSize)
|
|
112
|
-
.modifier(SideBarGlass(tintColor: tintColor, shape: Circle()))
|
|
113
|
-
.overlay(alignment: .topTrailing) {
|
|
114
|
-
if showBadge {
|
|
115
|
-
BadgeDot(size: .small).offset(x: -Spacing.XXS, y: Spacing.XXS)
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
.buttonStyle(.plain)
|
|
120
|
-
.accessibilityIdentifier(accessibilityId ?? "")
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/// 48pt wide glass capsule grouping related controls, one item per 50pt.
|
|
125
|
-
struct SideBarGroup<Content: View>: View {
|
|
126
|
-
var tintColor: Color?
|
|
127
|
-
let itemCount: Int
|
|
128
|
-
@ViewBuilder let content: () -> Content
|
|
129
|
-
|
|
130
|
-
var body: some View {
|
|
131
|
-
VStack(spacing: 0) { content() }
|
|
132
|
-
.frame(
|
|
133
|
-
width: DuoMetrics.controlSize,
|
|
134
|
-
height: itemCount > 1 ? DuoMetrics.itemPitch * CGFloat(itemCount) : DuoMetrics.controlSize
|
|
135
|
-
)
|
|
136
|
-
.modifier(SideBarGlass(tintColor: tintColor, shape: RoundedRectangle(cornerRadius: Radius.XL)))
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
struct SideBarGroupItem: View {
|
|
141
|
-
let icon: String
|
|
142
|
-
var tintColor: Color?
|
|
143
|
-
let accessibilityId: String
|
|
144
|
-
let action: () -> Void
|
|
145
|
-
|
|
146
|
-
var body: some View {
|
|
147
|
-
SwiftUI.Button(action: action) {
|
|
148
|
-
Icon(source: icon, size: sideBarIconSize, color: tintColor ?? Colors.black17)
|
|
149
|
-
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
|
150
|
-
.contentShape(Rectangle())
|
|
151
|
-
}
|
|
152
|
-
.buttonStyle(.plain)
|
|
153
|
-
.accessibilityIdentifier(accessibilityId)
|
|
154
|
-
}
|
|
155
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import SwiftUI
|
|
2
|
-
|
|
3
|
-
// Width of a system alert on the iPhone Duo inner display, in both orientations (RN Popup/utils.ts).
|
|
4
|
-
private let duoPopupMaxWidth: CGFloat = 440
|
|
5
|
-
|
|
6
|
-
extension ScreenLayout {
|
|
7
|
-
var isDuoDevice: Bool { isIPhoneDuoDevice(windowSize: CGSize(width: width, height: height)) }
|
|
8
|
-
|
|
9
|
-
/// Card width cap; other devices keep the full window width minus the popup's own padding.
|
|
10
|
-
var popupMaxWidth: CGFloat {
|
|
11
|
-
isDuoDevice ? min(width - Spacing.XL * 2, duoPopupMaxWidth) : .infinity
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/// Room left for a popup on iPhone Duo, where landscape is too short for it; nil elsewhere.
|
|
15
|
-
var popupMaxHeight: CGFloat? {
|
|
16
|
-
guard isDuoDevice else { return nil }
|
|
17
|
-
return height - duoTopInset - insets.bottom - Spacing.XL * 2
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/// Scrolls `content` once it is taller than `maxHeight`; otherwise sizes to it.
|
|
22
|
-
struct PopupScrollBody<Content: View>: View {
|
|
23
|
-
let maxHeight: CGFloat?
|
|
24
|
-
@ViewBuilder let content: () -> Content
|
|
25
|
-
|
|
26
|
-
@State private var contentHeight: CGFloat = 0
|
|
27
|
-
|
|
28
|
-
var body: some View {
|
|
29
|
-
if let maxHeight {
|
|
30
|
-
ScrollView(.vertical, showsIndicators: false) {
|
|
31
|
-
content()
|
|
32
|
-
.background(
|
|
33
|
-
GeometryReader { proxy in
|
|
34
|
-
Color.clear
|
|
35
|
-
.onAppear { contentHeight = proxy.size.height }
|
|
36
|
-
.onChange(of: proxy.size.height) { contentHeight = $0 }
|
|
37
|
-
}
|
|
38
|
-
)
|
|
39
|
-
}
|
|
40
|
-
.frame(height: min(contentHeight, max(maxHeight, 0)))
|
|
41
|
-
} else {
|
|
42
|
-
content()
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
package/ios-demo/README.md
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
# MoMoUIKitsDemo
|
|
2
|
-
|
|
3
|
-
SwiftUI demo browser for `MoMoUIKits`.
|
|
4
|
-
|
|
5
|
-
The package can optionally host a Compose UIKits screen by receiving a
|
|
6
|
-
`UIViewController` factory from the host app. It does not import the KMP
|
|
7
|
-
`shared` module directly.
|
|
8
|
-
|
|
9
|
-
SwiftUI mode reuses the full demo screen set from
|
|
10
|
-
`sample/iosApp/iosApp/Demo`, including the sample `HomeView` registry and demo
|
|
11
|
-
screens for all currently available components.
|
|
12
|
-
|
|
13
|
-
## CocoaPods
|
|
14
|
-
|
|
15
|
-
In the host app `Podfile`, include both local pods:
|
|
16
|
-
|
|
17
|
-
```ruby
|
|
18
|
-
pod 'MoMoUIKits', :path => '../momo-native-kits/ios/native-kits.podspec'
|
|
19
|
-
pod 'MoMoUIKitsDemo', :path => '../momo-native-kits/ios-demo'
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
Adjust the relative paths to match the host app checkout.
|
|
23
|
-
|
|
24
|
-
## Host App Usage
|
|
25
|
-
|
|
26
|
-
```swift
|
|
27
|
-
import MoMoUIKitsDemo
|
|
28
|
-
import shared
|
|
29
|
-
|
|
30
|
-
class UIKitsViewController: BaseComposeAppViewController {
|
|
31
|
-
override func getViewController() -> UIViewController? {
|
|
32
|
-
let params = self.application.data as? [String: Any]
|
|
33
|
-
|
|
34
|
-
return MoMoUIKitsDemoViewControllerFactory.make(
|
|
35
|
-
context: MoMoUIKitsDemoContext(
|
|
36
|
-
appId: params?["appId"] as? String ?? "",
|
|
37
|
-
appCode: params?["code"] as? String ?? "",
|
|
38
|
-
appName: params?["name"] as? String,
|
|
39
|
-
appIcon: params?["icon"] as? String ?? ""
|
|
40
|
-
),
|
|
41
|
-
composeViewController: {
|
|
42
|
-
UIKitsScreenComposeViewControllerKt.UIKitsScreenComposeViewController(
|
|
43
|
-
params: params
|
|
44
|
-
)
|
|
45
|
-
}
|
|
46
|
-
)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
override func viewDidDisappear(_ animated: Bool) {
|
|
50
|
-
super.viewDidDisappear(animated)
|
|
51
|
-
composeViewController = nil
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
If the host does not pass `composeViewController`, the demo opens directly in
|
|
57
|
-
SwiftUI mode.
|
|
58
|
-
|
|
59
|
-
## Included SwiftUI Demos
|
|
60
|
-
|
|
61
|
-
The pod includes the sample demo screens for:
|
|
62
|
-
|
|
63
|
-
- Animated Header
|
|
64
|
-
- Avatar
|
|
65
|
-
- Badge
|
|
66
|
-
- Baseline View
|
|
67
|
-
- Bottom Tab
|
|
68
|
-
- Button
|
|
69
|
-
- Carousel
|
|
70
|
-
- Checkbox
|
|
71
|
-
- Chip
|
|
72
|
-
- Collapse
|
|
73
|
-
- DateTimePicker
|
|
74
|
-
- Divider
|
|
75
|
-
- Header User
|
|
76
|
-
- Icon Button
|
|
77
|
-
- Image
|
|
78
|
-
- Information
|
|
79
|
-
- Input
|
|
80
|
-
- Input DropDown
|
|
81
|
-
- Input Money
|
|
82
|
-
- Input OTP
|
|
83
|
-
- Input Phone Number
|
|
84
|
-
- Input Search
|
|
85
|
-
- Input TextArea
|
|
86
|
-
- Loader
|
|
87
|
-
- Navigation
|
|
88
|
-
- Pagination
|
|
89
|
-
- Popup Display
|
|
90
|
-
- Popup Notify
|
|
91
|
-
- Popup Promotion
|
|
92
|
-
- Progress Info
|
|
93
|
-
- Radio
|
|
94
|
-
- Rating
|
|
95
|
-
- Skeleton
|
|
96
|
-
- Slider
|
|
97
|
-
- SnackBar
|
|
98
|
-
- Stepper
|
|
99
|
-
- Steps
|
|
100
|
-
- Suggest Action
|
|
101
|
-
- Swipe
|
|
102
|
-
- Switch
|
|
103
|
-
- TabView
|
|
104
|
-
- Tag
|
|
105
|
-
- Theme
|
|
106
|
-
- Title
|
|
107
|
-
- Tooltip
|
|
108
|
-
- Typography
|
|
109
|
-
- Uploader
|
|
110
|
-
|
|
111
|
-
## Validation Notes
|
|
112
|
-
|
|
113
|
-
Validated locally with:
|
|
114
|
-
|
|
115
|
-
```sh
|
|
116
|
-
pod ipc spec ios/MoMoUIKits.podspec
|
|
117
|
-
pod ipc spec ios-demo/MoMoUIKitsDemo.podspec
|
|
118
|
-
pod lib lint ios/MoMoUIKits.podspec --allow-warnings --skip-import-validation
|
|
119
|
-
pod lib lint ios-demo/MoMoUIKitsDemo.podspec --allow-warnings --skip-import-validation --include-podspecs=ios/MoMoUIKits.podspec
|
|
120
|
-
```
|