@momo-kits/native-kits 0.300.3 → 0.300.4-debug
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +51 -7
- package/README.md +2 -2
- package/build.gradle.kts +13 -0
- package/compose/build.gradle.kts +197 -0
- package/compose/build.gradle.kts.backup +197 -0
- package/compose/compose.podspec +47 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/const/HostFont.android.kt +20 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +6 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/BackGesture.android.kt +12 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +7 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +153 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/ReservedRegions.android.kt +6 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +110 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/DesignSystemKits.kt +62 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +1071 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +269 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +65 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +157 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +81 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +32 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +338 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +175 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +357 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +115 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +89 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +128 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +209 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +542 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +49 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +86 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +125 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +231 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +189 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +478 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +114 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +265 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +235 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +223 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +265 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +185 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +343 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +108 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +56 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +41 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +84 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +40 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +361 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +108 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +308 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +59 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +87 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +21 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +90 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +330 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +220 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +473 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +122 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +207 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +92 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +560 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +86 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +125 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +207 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +501 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +176 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +182 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +193 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +29 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +236 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +180 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +325 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/HostFont.kt +17 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +12 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +16 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +194 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +287 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +54 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +50 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/ScreenLayout.kt +306 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +41 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +52 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +66 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +11 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +104 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +48 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +51 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +338 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/HostBackGestureBridge.kt +58 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +137 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +116 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +215 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +404 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +8 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +732 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackTransition.kt +148 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/SwipeBackHaptic.kt +40 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +233 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +217 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +86 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoBarCompression.kt +97 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoTabBar.kt +377 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +169 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +455 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +103 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderJourney.kt +106 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderLocation.kt +74 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +413 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +39 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +363 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HelpCenterRequest.kt +37 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SideBar.kt +192 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +133 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/ToolkitRequests.kt +41 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +135 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/BackGesture.kt +12 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +91 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +9 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +74 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ReservedRegions.kt +20 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +1329 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +55 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +15 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +118 -0
- package/compose/src/commonTest/kotlin/vn/momo/kits/navigation/component/HelpCenterRequestTest.kt +44 -0
- package/compose/src/commonTest/kotlin/vn/momo/kits/navigation/component/ToolkitRequestsTest.kt +62 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/const/HostFont.ios.kt +42 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/HostBackGesture.ios.kt +45 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +36 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/BackGesture.ios.kt +38 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +66 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +217 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/ReservedRegions.ios.kt +138 -0
- package/gradle/libs.versions.toml +68 -0
- package/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/gradle/wrapper/gradle-wrapper.properties +8 -0
- package/gradle.properties +26 -0
- package/gradlew +252 -0
- package/gradlew.bat +94 -0
- package/ios/Application/ApplicationEnvironment.swift +24 -6
- package/ios/Application/DesignSystemKits.swift +100 -0
- package/ios/Application/DesignSystemKitsPayload.swift +68 -0
- package/ios/Application/MaxApi.swift +30 -3
- package/ios/Avatar/Avatar.swift +4 -3
- package/ios/Badge/Badge.swift +6 -4
- package/ios/Badge/BadgeDot.swift +1 -1
- package/ios/Badge/BadgeRibbon.swift +8 -2
- package/ios/Button/Button.swift +15 -12
- package/ios/CalculatorKeyboard/CalculatorKeyboard.swift +64 -18
- package/ios/Carousel/Carousel.swift +29 -12
- package/ios/Checkbox/Checkbox.swift +7 -3
- package/ios/Chip/Chip.swift +5 -4
- package/ios/Collapse/Collapse.swift +70 -19
- package/ios/Colors+Radius+Spacing/Colors.swift +10 -1
- package/ios/Colors+Radius+Spacing/Radius.swift +6 -0
- package/ios/DateTimePicker/DateTimePicker.swift +54 -20
- package/ios/DateTimePicker/WheelPicker.swift +103 -105
- package/ios/Divider/Divider.swift +37 -4
- package/ios/Extensions/Color++.swift +38 -9
- package/ios/Extensions/OptionalEnvironmentObject.swift +12 -0
- package/ios/Extensions/SkeletonUICompat.swift +11 -0
- package/ios/Icon/Icon.swift +21 -23
- package/ios/Icon/Icons.swift +1329 -0
- package/ios/IconButton/IconButton.swift +15 -7
- package/ios/Image/Image.swift +7 -23
- package/ios/Information/Information.swift +27 -9
- package/ios/Input/ErrorView.swift +2 -2
- package/ios/Input/Input.swift +171 -148
- package/ios/Input/InputPhoneNumber.swift +10 -9
- package/ios/Input/InputSearch.swift +107 -78
- package/ios/Input/InputTextArea.swift +133 -148
- package/ios/InputDropDown/InputDropDown.swift +10 -7
- package/ios/InputMoney/InputMoney.swift +32 -11
- package/ios/InputOTP/InputOTP.swift +22 -12
- package/ios/Layout/Card.swift +50 -0
- package/ios/Layout/GridContext.swift +187 -3
- package/ios/Layout/Item.swift +5 -4
- package/ios/Layout/ScreenLayout.swift +415 -0
- package/ios/Layout/Section.swift +4 -100
- package/ios/Loader/Loader.swift +5 -9
- package/ios/Lottie/LottieView.swift +14 -2
- package/ios/{Application/Navigation/Overplay → Navigation}/BottomSheet.swift +169 -29
- package/ios/Navigation/BottomTab/BottomTab.swift +332 -0
- package/ios/{Application/Navigation → Navigation}/BottomTab/BottomTabBar.swift +18 -7
- package/ios/Navigation/BottomTab/DuoBarCompression.swift +104 -0
- package/ios/Navigation/BottomTab/DuoTabBar.swift +329 -0
- package/ios/{Application → Navigation/Component}/FloatingButton.swift +43 -54
- package/ios/Navigation/Component/Header.swift +545 -0
- package/ios/Navigation/Component/HeaderBackground.swift +154 -0
- package/ios/Navigation/Component/HeaderJourney.swift +73 -0
- package/ios/Navigation/Component/HeaderLocation.swift +48 -0
- package/ios/Navigation/Component/HeaderRight.swift +425 -0
- package/ios/Navigation/Component/HeaderTitle.swift +36 -0
- package/ios/{Application/Navigation → Navigation/Component}/HeaderUser.swift +21 -24
- package/ios/Navigation/Component/SideBar.swift +183 -0
- package/ios/{Application/Navigation/Overplay → Navigation/Component}/SnackBar.swift +8 -8
- package/ios/Navigation/HostBackGestureBridge.swift +78 -0
- package/ios/{Application/Navigation/Overplay → Navigation}/ModalScreen.swift +9 -2
- package/ios/Navigation/Navigation.swift +204 -0
- package/ios/Navigation/NavigationContainer.swift +195 -0
- package/ios/{Application/Navigation → Navigation}/Navigator.swift +207 -107
- package/ios/Navigation/StackScreen.swift +930 -0
- package/ios/Navigation/StackTransition.swift +400 -0
- package/ios/Navigation/SwipeBackHaptic.swift +33 -0
- package/ios/{Application/Navigation → Navigation}/Tracking/ScreenTracker.swift +12 -5
- package/ios/OTPKeyboard/OTPKeyboard.swift +8 -11
- package/ios/Pagination/PaginationScroll.swift +2 -2
- package/ios/Popup/PopupDisplay.swift +72 -135
- package/ios/Popup/PopupInput.swift +10 -13
- package/ios/Popup/PopupLayout.swift +138 -0
- package/ios/Popup/PopupNotify.swift +59 -69
- package/ios/Popup/PopupPromotion.swift +31 -47
- package/ios/PopupView/FullscreenPopup.swift +13 -19
- package/ios/PopupView/PopupView.swift +1 -1
- package/ios/PopupView/Utils++.swift +0 -8
- package/ios/ProgressInfo/ProgressInfo.swift +4 -2
- package/ios/Radio/Radio.swift +2 -1
- package/ios/Rating/Rating.swift +9 -1
- package/ios/Resources/dot_loading.json +558 -0
- package/ios/Resources/lottie_circle_loader.json +1 -0
- package/ios/ScrollIndicator/ScrollIndicator.swift +11 -10
- package/ios/Skeleton/Skeleton.swift +22 -27
- package/ios/Slider/Slider.swift +16 -18
- package/ios/Stepper/Stepper.swift +7 -3
- package/ios/Steps/Steps.swift +8 -6
- package/ios/SuggestAction/SuggestAction.swift +5 -0
- package/ios/Swipeable/SwipeCell.swift +10 -6
- package/ios/Switch/Switch.swift +22 -20
- package/ios/TabView/TabView.swift +102 -21
- package/ios/Tag/Tag.swift +15 -4
- package/ios/Template/Logo/Logo.swift +2 -1
- package/ios/Template/TrustBanner/TrustBanner.swift +109 -55
- package/ios/Title/Title.swift +6 -17
- package/ios/Tooltip/Tooltip.swift +29 -14
- package/ios/Typography/FontScale.swift +17 -14
- package/ios/Typography/Text.swift +156 -20
- package/ios/Typography/Typography.swift +2 -2
- package/ios/Uploader/Uploader.swift +3 -1
- package/ios/native-kits.podspec +2 -3
- package/ios-demo/MoMoUIKitsDemo.podspec +1 -3
- package/ios-demo/README.md +120 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ContentView.swift +1 -1
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DuoTabDemo.swift +80 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +2 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IPhoneDuoDemo.swift +173 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/NavigationDemo.swift +77 -1
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupDisplayDemo.swift +1 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupNotifyDemo.swift +2 -2
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupPromotionDemo.swift +2 -0
- package/package.json +1 -1
- package/publish.sh +19 -2
- package/scripts/gen-ios-icons.mjs +36 -0
- package/settings.gradle.kts +64 -0
- package/ios/Application/Components.swift +0 -270
- package/ios/Application/ComposeApi.swift +0 -22
- package/ios/Application/HeaderRight.swift +0 -306
- package/ios/Application/Navigation/BottomTab/BottomTab.swift +0 -104
- package/ios/Application/Navigation/HeaderBackProps.swift +0 -66
- package/ios/Application/Navigation/HeaderTitle.swift +0 -57
- package/ios/Application/Navigation/NavigationContainer.swift +0 -213
- package/ios/Application/Navigation/NavigationOptions.swift +0 -109
- package/ios/Application/Navigation/NavigatorManager.swift +0 -22
- package/ios/Application/Navigation/component/Header.swift +0 -178
- package/ios/Application/Navigation/component/HeaderBackground.swift +0 -83
- package/ios/Application/Navigation/component/HeaderColor.swift +0 -65
- package/ios/Application/Navigation/component/HeaderRightWidthKey.swift +0 -11
- package/ios/Application/Navigation/component/NavigationFooter.swift +0 -90
- package/ios/Application/Navigation/component/NavigationHeaderRight.swift +0 -196
- package/ios/Application/Screen.swift +0 -250
- package/ios/Application/StackScreen.swift +0 -492
- package/ios/Typography/FontScaleStore.swift +0 -58
- package/ios/Typography/KitDesignSystem.swift +0 -17
- /package/ios/{Application/Navigation → Navigation}/BottomTab/CurvedContainer.swift +0 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
|
|
3
|
+
/// Rounded surface laid out on the kit grid (8pt gutter), inset by the screen margin.
|
|
4
|
+
/// Mirrors `vn.momo.kits.layout.Card`.
|
|
5
|
+
public struct CardView<Content: View>: View {
|
|
6
|
+
@Environment(\.appTheme) private var theme
|
|
7
|
+
|
|
8
|
+
// MARK: Lifecycle
|
|
9
|
+
|
|
10
|
+
public init(
|
|
11
|
+
useShadow: Bool = false,
|
|
12
|
+
backgroundImage: String? = nil,
|
|
13
|
+
backgroundColor: Color? = nil,
|
|
14
|
+
contentPadding: EdgeInsets = EdgeInsets(top: Spacing.M, leading: Spacing.M, bottom: Spacing.M, trailing: Spacing.M),
|
|
15
|
+
@ViewBuilder content: @escaping () -> Content
|
|
16
|
+
) {
|
|
17
|
+
self.useShadow = useShadow
|
|
18
|
+
self.backgroundImage = backgroundImage
|
|
19
|
+
self.backgroundColor = backgroundColor
|
|
20
|
+
self.contentPadding = contentPadding
|
|
21
|
+
self.content = content
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// MARK: Public
|
|
25
|
+
|
|
26
|
+
public var body: some View {
|
|
27
|
+
GridFlow(gutter: Spacing.S, content: content)
|
|
28
|
+
.padding(contentPadding)
|
|
29
|
+
.background(background)
|
|
30
|
+
.background(backgroundColor ?? theme.colors.background.surface)
|
|
31
|
+
.clipShape(RoundedRectangle(cornerRadius: Radius.M))
|
|
32
|
+
// Approximates Compose `shadow(6.dp)` elevation.
|
|
33
|
+
.shadow(color: Color.black.opacity(useShadow ? 0.12 : 0), radius: useShadow ? 6 : 0, x: 0, y: useShadow ? 3 : 0)
|
|
34
|
+
.padding(.horizontal, Spacing.M)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// MARK: Private
|
|
38
|
+
|
|
39
|
+
private let useShadow: Bool
|
|
40
|
+
private let backgroundImage: String?
|
|
41
|
+
private let backgroundColor: Color?
|
|
42
|
+
private let contentPadding: EdgeInsets
|
|
43
|
+
private let content: () -> Content
|
|
44
|
+
|
|
45
|
+
@ViewBuilder private var background: some View {
|
|
46
|
+
if let backgroundImage {
|
|
47
|
+
ImageView(backgroundImage, contentMode: .fill).clipped()
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -1,20 +1,31 @@
|
|
|
1
1
|
import SwiftUI
|
|
2
2
|
|
|
3
|
-
/// Grid metrics published by a layout container (`SectionView`) so span-based children
|
|
3
|
+
/// Grid metrics published by a layout container (`SectionView`, `CardView`) so span-based children
|
|
4
4
|
/// can size themselves. Mirrors `vn.momo.kits.layout.GridContext`.
|
|
5
5
|
public struct GridContext: Equatable {
|
|
6
6
|
public let numberOfColumns: Int
|
|
7
7
|
public let gutter: CGFloat
|
|
8
8
|
public let sizePerSpan: CGFloat
|
|
9
|
+
/// Pixels per point; span sizes are floored onto the pixel grid when it is set.
|
|
10
|
+
public let displayScale: CGFloat
|
|
9
11
|
|
|
10
|
-
public init(
|
|
12
|
+
public init(
|
|
13
|
+
numberOfColumns: Int = 12,
|
|
14
|
+
gutter: CGFloat = Spacing.M,
|
|
15
|
+
sizePerSpan: CGFloat = 0,
|
|
16
|
+
displayScale: CGFloat = 0
|
|
17
|
+
) {
|
|
11
18
|
self.numberOfColumns = numberOfColumns
|
|
12
19
|
self.gutter = gutter
|
|
13
20
|
self.sizePerSpan = sizePerSpan
|
|
21
|
+
self.displayScale = displayScale
|
|
14
22
|
}
|
|
15
23
|
|
|
16
24
|
public func sizeForSpan(_ span: Int) -> CGFloat {
|
|
17
|
-
sizePerSpan * CGFloat(span) + gutter * CGFloat(span - 1)
|
|
25
|
+
let size = sizePerSpan * CGFloat(span) + gutter * CGFloat(span - 1)
|
|
26
|
+
guard displayScale > 0 else { return size }
|
|
27
|
+
// Compose floors in pixels so a full row of spans never overflows by a sub-pixel.
|
|
28
|
+
return floor(size * displayScale) / displayScale
|
|
18
29
|
}
|
|
19
30
|
}
|
|
20
31
|
|
|
@@ -28,3 +39,176 @@ public extension EnvironmentValues {
|
|
|
28
39
|
set { self[GridContextKey.self] = newValue }
|
|
29
40
|
}
|
|
30
41
|
}
|
|
42
|
+
|
|
43
|
+
/// Measures the width it is given, publishes the grid for it and wraps children in a flow row.
|
|
44
|
+
/// Shared body of `SectionView` and `CardView` (Compose `gridColumns()` + `gridContext()` + `FlowRow`).
|
|
45
|
+
struct GridFlow<Content: View>: View {
|
|
46
|
+
let gutter: CGFloat
|
|
47
|
+
let content: () -> Content
|
|
48
|
+
|
|
49
|
+
@Environment(\.screenLayout) private var screenLayout
|
|
50
|
+
@Environment(\.displayScale) private var displayScale
|
|
51
|
+
/// The Compose `BoxWithConstraints` width.
|
|
52
|
+
@State private var availableWidth: CGFloat = 0
|
|
53
|
+
|
|
54
|
+
var body: some View {
|
|
55
|
+
flow
|
|
56
|
+
.environment(\.gridContext, grid)
|
|
57
|
+
.frame(maxWidth: .infinity, alignment: .topLeading)
|
|
58
|
+
.background(widthReader)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private var grid: GridContext {
|
|
62
|
+
let columns = screenLayout.contentWidth > 600 ? 24 : 12
|
|
63
|
+
let column = (availableWidth - gutter * CGFloat(columns - 1)) / CGFloat(columns)
|
|
64
|
+
return GridContext(
|
|
65
|
+
numberOfColumns: columns,
|
|
66
|
+
gutter: gutter,
|
|
67
|
+
sizePerSpan: max(0, column),
|
|
68
|
+
displayScale: displayScale
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@ViewBuilder private var flow: some View {
|
|
73
|
+
if #available(iOS 16.0, *) {
|
|
74
|
+
FlowRowLayout(gutter: gutter) { content() }
|
|
75
|
+
} else {
|
|
76
|
+
_VariadicView.Tree(FlowRowFallback(gutter: gutter, maxWidth: availableWidth)) { content() }
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private var widthReader: some View {
|
|
81
|
+
GeometryReader { proxy in
|
|
82
|
+
Color.clear.preference(key: GridWidthKey.self, value: proxy.size.width)
|
|
83
|
+
}
|
|
84
|
+
.onPreferenceChange(GridWidthKey.self) { availableWidth = $0 }
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private struct GridWidthKey: PreferenceKey {
|
|
89
|
+
static var defaultValue: CGFloat = 0
|
|
90
|
+
|
|
91
|
+
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
|
|
92
|
+
value = max(value, nextValue())
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/// iOS 15 has no `Layout`: the children are measured, then pinned to the same rows as
|
|
97
|
+
/// `FlowRowLayout` through alignment guides.
|
|
98
|
+
private struct FlowRowFallback: _VariadicView_UnaryViewRoot {
|
|
99
|
+
let gutter: CGFloat
|
|
100
|
+
let maxWidth: CGFloat
|
|
101
|
+
|
|
102
|
+
func body(children: _VariadicView.Children) -> some View {
|
|
103
|
+
FlowRowPlacement(children: children, gutter: gutter, maxWidth: maxWidth)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private struct FlowRowPlacement: View {
|
|
108
|
+
let children: _VariadicView.Children
|
|
109
|
+
let gutter: CGFloat
|
|
110
|
+
let maxWidth: CGFloat
|
|
111
|
+
@State private var sizes: [AnyHashable: CGSize] = [:]
|
|
112
|
+
|
|
113
|
+
var body: some View {
|
|
114
|
+
let placement = place()
|
|
115
|
+
ZStack(alignment: .topLeading) {
|
|
116
|
+
ForEach(children) { child in
|
|
117
|
+
child
|
|
118
|
+
// FlowRowLayout proposes no height
|
|
119
|
+
.fixedSize(horizontal: false, vertical: true)
|
|
120
|
+
.background(
|
|
121
|
+
GeometryReader { proxy in
|
|
122
|
+
Color.clear.preference(key: FlowChildSizesKey.self, value: [child.id: proxy.size])
|
|
123
|
+
}
|
|
124
|
+
)
|
|
125
|
+
.alignmentGuide(.leading) { _ in -(placement.origins[child.id]?.x ?? 0) }
|
|
126
|
+
.alignmentGuide(.top) { _ in -(placement.origins[child.id]?.y ?? 0) }
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
.frame(height: placement.height, alignment: .topLeading)
|
|
130
|
+
.onPreferenceChange(FlowChildSizesKey.self) { sizes = $0 }
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
private func place() -> (origins: [AnyHashable: CGPoint], height: CGFloat) {
|
|
134
|
+
var origins: [AnyHashable: CGPoint] = [:]
|
|
135
|
+
var x: CGFloat = 0
|
|
136
|
+
var y: CGFloat = 0
|
|
137
|
+
var rowHeight: CGFloat = 0
|
|
138
|
+
for child in children {
|
|
139
|
+
let size = sizes[child.id] ?? .zero
|
|
140
|
+
// Sub-point tolerance: spans are computed to land exactly on `maxWidth`.
|
|
141
|
+
if x > 0, x + size.width > maxWidth + 0.5 {
|
|
142
|
+
x = 0
|
|
143
|
+
y += rowHeight + gutter
|
|
144
|
+
rowHeight = 0
|
|
145
|
+
}
|
|
146
|
+
origins[child.id] = CGPoint(x: x, y: y)
|
|
147
|
+
x += size.width + gutter
|
|
148
|
+
rowHeight = max(rowHeight, size.height)
|
|
149
|
+
}
|
|
150
|
+
return (origins, y + rowHeight)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
private struct FlowChildSizesKey: PreferenceKey {
|
|
155
|
+
static var defaultValue: [AnyHashable: CGSize] = [:]
|
|
156
|
+
|
|
157
|
+
static func reduce(value: inout [AnyHashable: CGSize], nextValue: () -> [AnyHashable: CGSize]) {
|
|
158
|
+
value.merge(nextValue()) { $1 }
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/// Wrapping row with equal horizontal/vertical spacing — the Compose `FlowRow` equivalent.
|
|
163
|
+
@available(iOS 16.0, *)
|
|
164
|
+
private struct FlowRowLayout: Layout {
|
|
165
|
+
struct Row {
|
|
166
|
+
var items: [(index: Int, size: CGSize)] = []
|
|
167
|
+
var width: CGFloat = 0
|
|
168
|
+
var height: CGFloat = 0
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
let gutter: CGFloat
|
|
172
|
+
|
|
173
|
+
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout Void) -> CGSize {
|
|
174
|
+
let maxWidth = proposal.width ?? .infinity
|
|
175
|
+
let rows = rows(for: subviews, maxWidth: maxWidth)
|
|
176
|
+
let height = rows.reduce(0) { $0 + $1.height } + gutter * CGFloat(max(0, rows.count - 1))
|
|
177
|
+
return CGSize(width: proposal.width ?? rows.map(\.width).max() ?? 0, height: height)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout Void) {
|
|
181
|
+
var y = bounds.minY
|
|
182
|
+
for row in rows(for: subviews, maxWidth: bounds.width) {
|
|
183
|
+
var x = bounds.minX
|
|
184
|
+
for item in row.items {
|
|
185
|
+
subviews[item.index].place(
|
|
186
|
+
at: CGPoint(x: x, y: y),
|
|
187
|
+
anchor: .topLeading,
|
|
188
|
+
proposal: ProposedViewSize(item.size)
|
|
189
|
+
)
|
|
190
|
+
x += item.size.width + gutter
|
|
191
|
+
}
|
|
192
|
+
y += row.height + gutter
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private func rows(for subviews: Subviews, maxWidth: CGFloat) -> [Row] {
|
|
197
|
+
var rows: [Row] = []
|
|
198
|
+
var current = Row()
|
|
199
|
+
for index in subviews.indices {
|
|
200
|
+
let size = subviews[index].sizeThatFits(ProposedViewSize(width: maxWidth, height: nil))
|
|
201
|
+
let widthIfAppended = current.items.isEmpty ? size.width : current.width + gutter + size.width
|
|
202
|
+
// Sub-point tolerance: spans are computed to land exactly on `maxWidth`.
|
|
203
|
+
if !current.items.isEmpty, widthIfAppended > maxWidth + 0.5 {
|
|
204
|
+
rows.append(current)
|
|
205
|
+
current = Row()
|
|
206
|
+
}
|
|
207
|
+
current.width = current.items.isEmpty ? size.width : current.width + gutter + size.width
|
|
208
|
+
current.height = max(current.height, size.height)
|
|
209
|
+
current.items.append((index, size))
|
|
210
|
+
}
|
|
211
|
+
if !current.items.isEmpty { rows.append(current) }
|
|
212
|
+
return rows
|
|
213
|
+
}
|
|
214
|
+
}
|
package/ios/Layout/Item.swift
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import SwiftUI
|
|
2
2
|
|
|
3
|
-
/// Span-sized cell inside a `SectionView`. Reads the grid published by its container;
|
|
3
|
+
/// Span-sized cell inside a `SectionView` / `CardView`. Reads the grid published by its container;
|
|
4
4
|
/// without one it just wraps its content. Mirrors `vn.momo.kits.layout.Item`.
|
|
5
5
|
public struct ItemView<Content: View>: View {
|
|
6
6
|
// MARK: Lifecycle
|
|
7
7
|
|
|
8
|
+
/// `widthSpan` nil spans the full row, whatever the container's column count.
|
|
8
9
|
public init(
|
|
9
|
-
widthSpan: Int =
|
|
10
|
+
widthSpan: Int? = nil,
|
|
10
11
|
heightSpan: Int = 0,
|
|
11
12
|
@ViewBuilder content: @escaping () -> Content
|
|
12
13
|
) {
|
|
@@ -26,14 +27,14 @@ public struct ItemView<Content: View>: View {
|
|
|
26
27
|
|
|
27
28
|
// MARK: Private
|
|
28
29
|
|
|
29
|
-
private let widthSpan: Int
|
|
30
|
+
private let widthSpan: Int?
|
|
30
31
|
private let heightSpan: Int
|
|
31
32
|
private let content: () -> Content
|
|
32
33
|
|
|
33
34
|
@Environment(\.gridContext) private var grid
|
|
34
35
|
|
|
35
36
|
private var width: CGFloat? {
|
|
36
|
-
grid.map { $0.sizeForSpan(widthSpan) }
|
|
37
|
+
grid.map { $0.sizeForSpan(widthSpan ?? $0.numberOfColumns) }
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
private var height: CGFloat? {
|