@momo-kits/native-kits 0.152.4-beta.1 → 0.152.4-beta.10
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/CODE_OF_CONDUCT.md +133 -0
- package/CONTRIBUTING.md +114 -0
- package/LICENSE +20 -0
- package/README.md +7 -0
- package/build.gradle.kts +32 -0
- package/compose/MoMoComposeKits.podspec +54 -0
- package/compose/build.gradle.kts +149 -0
- package/compose/src/androidMain/AndroidManifest.xml +2 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +105 -0
- package/compose/src/commonMain/composeResources/files/lottie_circle_loader.json +1 -0
- package/compose/src/commonMain/composeResources/font/momosignature.otf +0 -0
- package/compose/src/commonMain/composeResources/font/momotrustdisplay.otf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_black.otf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_black.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_bold.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_heavy.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_light.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_medium.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_regular.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_semibold.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_thin.otf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_thin.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.otf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.ttf +0 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +57 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +201 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +222 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +48 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +86 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +76 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +76 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +306 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +33 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +715 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +214 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +236 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +69 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +77 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +27 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +334 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +345 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +90 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +131 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +543 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +23 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +58 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +143 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +179 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +111 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +384 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +160 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +234 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +223 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +232 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +236 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +228 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +364 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +50 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +34 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +85 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +33 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +338 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +95 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +64 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +89 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +91 -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 +84 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +208 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +172 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +199 -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 +237 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +191 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +306 -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 +13 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +191 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +258 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +2 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +35 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +2 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +59 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +68 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +11 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +49 -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 +232 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +111 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +94 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +159 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +232 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScaleSizeScope.kt +17 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +459 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +169 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +216 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +86 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +180 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +251 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +80 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +306 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +31 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +385 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +38 -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 +62 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +88 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +144 -0
- package/gradle.properties +19 -0
- package/gradlew +240 -0
- package/gradlew.bat +91 -0
- package/ios/Application/ApplicationEnvironment.swift +50 -0
- package/ios/Application/Components.swift +263 -0
- package/ios/Application/ComposeApi.swift +22 -0
- package/ios/Application/FloatingButton.swift +172 -0
- package/ios/Application/HeaderRight.swift +271 -0
- package/ios/Application/Screen.swift +249 -0
- package/ios/Badge/Badge.swift +85 -0
- package/ios/Badge/BadgeDot.swift +31 -0
- package/ios/Badge/BadgeRibbon.swift +174 -0
- package/ios/Button/Button.swift +211 -0
- package/ios/CalculatorKeyboard/CalculatorKeyboard.swift +126 -0
- package/ios/Checkbox/Checkbox.swift +81 -0
- package/ios/Chip/Chip.swift +96 -0
- package/ios/Colors+Radius+Spacing/Colors.swift +172 -0
- package/ios/Colors+Radius+Spacing/Radius.swift +22 -0
- package/ios/Colors+Radius+Spacing/Spacing.swift +12 -0
- package/ios/Extensions/Color++.swift +25 -0
- package/ios/Icon/Icon.swift +51 -0
- package/ios/Image/Image.swift +70 -0
- package/ios/Input/Input.swift +207 -0
- package/ios/Input/InputPhoneNumber.swift +176 -0
- package/ios/Input/InputSearch.swift +238 -0
- package/ios/Input/InputTextArea.swift +242 -0
- package/ios/Lottie/LottieView.swift +86 -0
- package/ios/OTPKeyboard/KeyboardButton.swift +41 -0
- package/ios/OTPKeyboard/OTPKeyboard.swift +145 -0
- package/ios/Popup/PopupDisplay.swift +284 -0
- package/ios/Popup/PopupInput.swift +96 -0
- package/ios/Popup/PopupPromotion.swift +73 -0
- package/ios/PopupView/FullscreenPopup.swift +251 -0
- package/ios/PopupView/Modifiers.swift +158 -0
- package/ios/PopupView/PopupView.swift +289 -0
- package/ios/PopupView/Utils++.swift +281 -0
- package/ios/ScrollIndicator/ScrollIndicator.swift +110 -0
- package/ios/Swipeable/SwipeCell.swift +278 -0
- package/ios/Swipeable/SwipeCellModel.swift +86 -0
- package/ios/Switch/Switch.swift +44 -0
- package/ios/Template/Logo/Logo.swift +75 -0
- package/ios/Template/TrustBanner/TrustBanner.swift +120 -0
- package/ios/Theme.md +18 -0
- package/ios/Typography/Text.swift +140 -0
- package/ios/Typography/Typography.swift +95 -0
- package/ios/native-kits.podspec +18 -0
- package/package.json +6 -7
- package/settings.gradle.kts +25 -0
- package/shared/build.gradle.kts +0 -74
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
|
|
3
|
+
public enum RibbonPosition {
|
|
4
|
+
case topLeft
|
|
5
|
+
case topRight
|
|
6
|
+
case bottomLeft
|
|
7
|
+
case bottomRight
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
public struct BadgeRibbon: View {
|
|
11
|
+
let position: RibbonPosition
|
|
12
|
+
let label: String
|
|
13
|
+
let isRound: Bool
|
|
14
|
+
let backgroundColor: Color
|
|
15
|
+
|
|
16
|
+
public init(
|
|
17
|
+
position: RibbonPosition = .topRight,
|
|
18
|
+
label: String = "Label",
|
|
19
|
+
isRound: Bool = false,
|
|
20
|
+
backgroundColor: Color? = nil
|
|
21
|
+
) {
|
|
22
|
+
self.position = position
|
|
23
|
+
self.label = label
|
|
24
|
+
self.isRound = isRound
|
|
25
|
+
self.backgroundColor = backgroundColor ?? Colors.orange03
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private var rotation: Angle {
|
|
29
|
+
switch position {
|
|
30
|
+
case .topRight, .bottomRight:
|
|
31
|
+
return .degrees(180)
|
|
32
|
+
case .topLeft, .bottomLeft:
|
|
33
|
+
return .zero
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private var useUpTail: Bool {
|
|
38
|
+
position == .bottomLeft || position == .topRight
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private var verticalAlignment: VerticalAlignment {
|
|
42
|
+
switch position {
|
|
43
|
+
case .topLeft, .bottomRight:
|
|
44
|
+
return .top
|
|
45
|
+
case .bottomLeft, .topRight:
|
|
46
|
+
return .bottom
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public var body: some View {
|
|
51
|
+
HStack(alignment: verticalAlignment, spacing: 0) {
|
|
52
|
+
if useUpTail {
|
|
53
|
+
upTail
|
|
54
|
+
} else {
|
|
55
|
+
downTail
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if isRound {
|
|
59
|
+
roundContent
|
|
60
|
+
} else {
|
|
61
|
+
skewContent
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
.frame(height: RibbonConstants.ribbonHeight)
|
|
65
|
+
.rotationEffect(rotation)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private var roundContent: some View {
|
|
69
|
+
HStack(spacing: 0) {
|
|
70
|
+
Text(label)
|
|
71
|
+
.font(.system(size: 12, weight: .medium))
|
|
72
|
+
.foregroundColor(Colors.black01)
|
|
73
|
+
.lineLimit(1)
|
|
74
|
+
.rotationEffect(rotation)
|
|
75
|
+
}
|
|
76
|
+
.frame(height: RibbonConstants.roundHeight)
|
|
77
|
+
.padding(.trailing, RibbonConstants.roundPaddingEnd)
|
|
78
|
+
.background(
|
|
79
|
+
RoundedRectangle(cornerRadius: Radius.M)
|
|
80
|
+
.fill(backgroundColor)
|
|
81
|
+
.mask(
|
|
82
|
+
HStack(spacing: 0) {
|
|
83
|
+
Rectangle()
|
|
84
|
+
RoundedRectangle(cornerRadius: Radius.M)
|
|
85
|
+
}
|
|
86
|
+
)
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private var skewContent: some View {
|
|
91
|
+
HStack(spacing: 0) {
|
|
92
|
+
Text(label)
|
|
93
|
+
.font(.system(size: 12, weight: .medium))
|
|
94
|
+
.foregroundColor(Colors.black01)
|
|
95
|
+
.lineLimit(1)
|
|
96
|
+
.rotationEffect(rotation)
|
|
97
|
+
.frame(height: RibbonConstants.skewBodyHeight)
|
|
98
|
+
.padding(.horizontal, 8)
|
|
99
|
+
.background(backgroundColor)
|
|
100
|
+
|
|
101
|
+
rightTail
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private var upTail: some View {
|
|
106
|
+
ImageView(
|
|
107
|
+
"https://static.momocdn.net/app/img/kits/utils/Head_down_4x.png",
|
|
108
|
+
placeholder: AnyView(Color.clear)
|
|
109
|
+
)
|
|
110
|
+
.frame(width: RibbonConstants.headTailWidth, height: RibbonConstants.headTailHeight)
|
|
111
|
+
.rotationEffect(.degrees(180))
|
|
112
|
+
.offset(x: 1)
|
|
113
|
+
.clipped()
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private var downTail: some View {
|
|
117
|
+
ImageView(
|
|
118
|
+
"https://static.momocdn.net/app/img/kits/utils/Head_4x.png",
|
|
119
|
+
placeholder: AnyView(Color.clear)
|
|
120
|
+
)
|
|
121
|
+
.frame(width: RibbonConstants.headTailWidth, height: RibbonConstants.headTailHeight)
|
|
122
|
+
.offset(x: 1)
|
|
123
|
+
.clipped()
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
private var rightTail: some View {
|
|
127
|
+
ImageView(
|
|
128
|
+
"https://static.momocdn.net/app/img/kits/utils/Tail_4x.png",
|
|
129
|
+
placeholder: AnyView(Color.clear)
|
|
130
|
+
)
|
|
131
|
+
.frame(width: RibbonConstants.skewTailWidth, height: RibbonConstants.skewTailHeight)
|
|
132
|
+
.offset(x: -2)
|
|
133
|
+
.clipped()
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// MARK: - Constants
|
|
138
|
+
private struct RibbonConstants {
|
|
139
|
+
static let ribbonHeight: CGFloat = 20
|
|
140
|
+
static let roundHeight: CGFloat = 16
|
|
141
|
+
static let skewBodyHeight: CGFloat = 16
|
|
142
|
+
static let roundRightRadius: CGFloat = 12
|
|
143
|
+
static let roundPaddingEnd: CGFloat = 6
|
|
144
|
+
static let skewTailWidth: CGFloat = 8
|
|
145
|
+
static let skewTailHeight: CGFloat = 16
|
|
146
|
+
static let headTailWidth: CGFloat = 5
|
|
147
|
+
static let headTailHeight: CGFloat = 20
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// MARK: - String Extension for Text Size
|
|
151
|
+
extension String {
|
|
152
|
+
func size(withAttributes attributes: [NSAttributedString.Key: Any]?) -> CGSize {
|
|
153
|
+
let size = (self as NSString).size(withAttributes: attributes)
|
|
154
|
+
return size
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// MARK: - Preview
|
|
159
|
+
#if DEBUG
|
|
160
|
+
struct BadgeRibbon_Previews: PreviewProvider {
|
|
161
|
+
static var previews: some View {
|
|
162
|
+
VStack(spacing: 30) {
|
|
163
|
+
// Basic ribbon examples
|
|
164
|
+
BadgeRibbon(position: .topRight, label: "New")
|
|
165
|
+
BadgeRibbon(position: .topLeft, label: "Hot", isRound: true)
|
|
166
|
+
BadgeRibbon(position: .bottomLeft, label: "Sale")
|
|
167
|
+
BadgeRibbon(position: .bottomRight, label: "50% OFF", isRound: true)
|
|
168
|
+
}
|
|
169
|
+
.padding()
|
|
170
|
+
.previewLayout(.sizeThatFits)
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
#endif
|
|
174
|
+
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import SwiftUI
|
|
3
|
+
import Lottie
|
|
4
|
+
|
|
5
|
+
// MARK: - ButtonType
|
|
6
|
+
|
|
7
|
+
public enum ButtonType {
|
|
8
|
+
case primary
|
|
9
|
+
case secondary
|
|
10
|
+
case tonal
|
|
11
|
+
case outline
|
|
12
|
+
case danger
|
|
13
|
+
case text
|
|
14
|
+
case disabled
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// MARK: - ButtonSize
|
|
18
|
+
|
|
19
|
+
public enum ButtonSize {
|
|
20
|
+
case large
|
|
21
|
+
case medium
|
|
22
|
+
case small
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public struct ButtonStyleData {
|
|
26
|
+
let background: Color
|
|
27
|
+
let content: Color
|
|
28
|
+
let border: Color?
|
|
29
|
+
let borderWidth: CGFloat
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public extension ButtonType {
|
|
33
|
+
func backgroundColor(loading: Bool) -> Color {
|
|
34
|
+
switch self {
|
|
35
|
+
case .disabled: return Colors.black05.opacity(loading ? 0.75 : 1)
|
|
36
|
+
case .primary: return Colors.primary.opacity(loading ? 0.75 : 1)
|
|
37
|
+
case .secondary: return Colors.card.opacity(loading ? 0.75 : 1)
|
|
38
|
+
case .outline: return Colors.card.opacity(loading ? 0.75 : 1)
|
|
39
|
+
case .tonal: return Colors.primaryLight.opacity(loading ? 0.75 : 1)
|
|
40
|
+
case .danger: return Colors.error.opacity(loading ? 0.75 : 1)
|
|
41
|
+
case .text: return .clear
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
func contentColor(loading: Bool) -> Color {
|
|
46
|
+
switch self {
|
|
47
|
+
case .disabled: return Colors.black06.opacity(loading ? 0.75 : 1)
|
|
48
|
+
case .primary: return Colors.black01
|
|
49
|
+
case .secondary: return Colors.black17
|
|
50
|
+
case .outline: return Colors.primary
|
|
51
|
+
case .tonal: return Colors.primary
|
|
52
|
+
case .danger: return Colors.black01
|
|
53
|
+
case .text: return Colors.primary
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
var borderColor: Color? {
|
|
58
|
+
switch self {
|
|
59
|
+
case .outline: return Colors.primary
|
|
60
|
+
case .secondary: return Colors.black04
|
|
61
|
+
default: return nil
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
var borderWidth: CGFloat {
|
|
66
|
+
switch self {
|
|
67
|
+
case .outline: return 1
|
|
68
|
+
case .secondary: return 1
|
|
69
|
+
default: return 0
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
extension ButtonSize {
|
|
75
|
+
var height: CGFloat {
|
|
76
|
+
switch self {
|
|
77
|
+
case .large: return 48
|
|
78
|
+
case .medium: return 36
|
|
79
|
+
case .small: return 28
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
var padding: CGFloat {
|
|
84
|
+
switch self {
|
|
85
|
+
case .large: return Spacing.L
|
|
86
|
+
case .medium: return Spacing.M
|
|
87
|
+
case .small: return Spacing.S
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
var radius: CGFloat {
|
|
92
|
+
Radius.S
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
var iconSize: CGFloat {
|
|
96
|
+
switch self {
|
|
97
|
+
case .large: return 24
|
|
98
|
+
case .medium, .small: return 16
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
var iconSpacing: CGFloat {
|
|
103
|
+
switch self {
|
|
104
|
+
case .small: return Spacing.XS
|
|
105
|
+
case .medium, .large: return Spacing.S
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
var font: Font {
|
|
110
|
+
switch self {
|
|
111
|
+
case .large: return .system(size: 16, weight: .bold)
|
|
112
|
+
case .medium: return .system(size: 14, weight: .bold)
|
|
113
|
+
case .small: return .system(size: 12, weight: .bold)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public struct Button: View {
|
|
119
|
+
|
|
120
|
+
var title: String
|
|
121
|
+
var action: () -> Void
|
|
122
|
+
var type: ButtonType
|
|
123
|
+
var size: ButtonSize
|
|
124
|
+
var iconLeft: AnyView?
|
|
125
|
+
var iconRight: AnyView?
|
|
126
|
+
var loading: Bool
|
|
127
|
+
|
|
128
|
+
public init(
|
|
129
|
+
title: String = "",
|
|
130
|
+
action: @escaping () -> Void,
|
|
131
|
+
type: ButtonType = .primary,
|
|
132
|
+
size: ButtonSize = .large,
|
|
133
|
+
iconLeft: AnyView? = nil,
|
|
134
|
+
iconRight: AnyView? = nil,
|
|
135
|
+
loading: Bool = false
|
|
136
|
+
) {
|
|
137
|
+
self.title = title
|
|
138
|
+
self.action = action
|
|
139
|
+
self.type = type
|
|
140
|
+
self.size = size
|
|
141
|
+
self.iconLeft = iconLeft
|
|
142
|
+
self.iconRight = iconRight
|
|
143
|
+
self.loading = loading
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
private func shouldLoadingOnLeft(_ left: AnyView?, _ right: AnyView?) -> Bool {
|
|
147
|
+
let hasLeft = left != nil
|
|
148
|
+
let hasRight = right != nil
|
|
149
|
+
|
|
150
|
+
switch (hasLeft, hasRight) {
|
|
151
|
+
case (false, false): return true
|
|
152
|
+
case (true, false): return true
|
|
153
|
+
case (false, true): return false
|
|
154
|
+
case (true, true): return false
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
public var body: some View {
|
|
159
|
+
|
|
160
|
+
let loadingOnLeft = shouldLoadingOnLeft(iconLeft, iconRight)
|
|
161
|
+
|
|
162
|
+
let bg = type.backgroundColor(loading: loading)
|
|
163
|
+
let fg = type.contentColor(loading: loading)
|
|
164
|
+
let border = type.borderColor
|
|
165
|
+
let borderWidth = type.borderWidth
|
|
166
|
+
|
|
167
|
+
SwiftUI.Button(action: {
|
|
168
|
+
if !loading && type != .disabled {
|
|
169
|
+
action()
|
|
170
|
+
}
|
|
171
|
+
}) {
|
|
172
|
+
HStack(spacing: size.iconSpacing) {
|
|
173
|
+
|
|
174
|
+
if loading && loadingOnLeft {
|
|
175
|
+
LottieView(name: "lottie_circle_loader", loopMode: .loop)
|
|
176
|
+
.frame(width: size.iconSize, height: size.iconSize)
|
|
177
|
+
.colorMultiply(fg)
|
|
178
|
+
|
|
179
|
+
} else if let iconLeft = iconLeft {
|
|
180
|
+
iconLeft.frame(width: size.iconSize, height: size.iconSize)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
Text(title)
|
|
184
|
+
.font(size.font)
|
|
185
|
+
.foregroundColor(fg)
|
|
186
|
+
.lineLimit(1)
|
|
187
|
+
.truncationMode(.tail)
|
|
188
|
+
|
|
189
|
+
if loading && !loadingOnLeft {
|
|
190
|
+
LottieView(name: "lottie_circle_loader", loopMode: .loop)
|
|
191
|
+
.frame(width: size.iconSize, height: size.iconSize)
|
|
192
|
+
.colorMultiply(fg)
|
|
193
|
+
|
|
194
|
+
} else if let iconRight = iconRight {
|
|
195
|
+
iconRight.frame(width: size.iconSize, height: size.iconSize)
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
.frame(maxWidth: .infinity)
|
|
199
|
+
.padding(.horizontal, size.padding)
|
|
200
|
+
.frame(height: size.height)
|
|
201
|
+
.background(bg)
|
|
202
|
+
.overlay(
|
|
203
|
+
RoundedRectangle(cornerRadius: size.radius)
|
|
204
|
+
.stroke(border ?? .clear, lineWidth: border != nil ? borderWidth : 0)
|
|
205
|
+
)
|
|
206
|
+
.clipShape(RoundedRectangle(cornerRadius: size.radius))
|
|
207
|
+
.opacity(loading ? 0.75 : 1)
|
|
208
|
+
}
|
|
209
|
+
.disabled(type == .disabled || loading)
|
|
210
|
+
}
|
|
211
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
|
|
2
|
+
import Foundation
|
|
3
|
+
import SwiftUI
|
|
4
|
+
|
|
5
|
+
// MARK: - CalculatorKeyboard
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
extension String {
|
|
9
|
+
var isNumber: Bool {
|
|
10
|
+
let digitsCharacters = CharacterSet(charactersIn: "0123456789")
|
|
11
|
+
return CharacterSet(charactersIn: self).isSubset(of: digitsCharacters)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
public struct CalculatorKeyboard: View {
|
|
17
|
+
// MARK: Lifecycle
|
|
18
|
+
@Binding var value: String
|
|
19
|
+
@State var tempValue: String = ""
|
|
20
|
+
|
|
21
|
+
public init(_ value: Binding<String>) {
|
|
22
|
+
self._value = value
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
func onPressBack(){
|
|
26
|
+
if (value.count > 0 ){
|
|
27
|
+
value.removeLast()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
func onPressClear(key: String){
|
|
33
|
+
value = ""
|
|
34
|
+
tempValue = ""
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
func onPressEqual(key: String){
|
|
38
|
+
if (tempValue == "") {
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
if (tempValue.last?.isNumber == false){
|
|
42
|
+
tempValue.removeLast()
|
|
43
|
+
}
|
|
44
|
+
let expression = NSExpression(format: tempValue)
|
|
45
|
+
|
|
46
|
+
value = String(expression.expressionValue(with: nil, context: nil) as! Int)
|
|
47
|
+
if (Int(value) ?? 0 < 0){
|
|
48
|
+
value = ""
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
func onPressKey(key:String){
|
|
53
|
+
if (tempValue.last?.isNumber == false){
|
|
54
|
+
if (key.isNumber == false){
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
var convertedKey = key
|
|
59
|
+
if (key == "x") {convertedKey = "*"}
|
|
60
|
+
if (key == "÷") {convertedKey = "/"}
|
|
61
|
+
if (value == "" && (key == "0" || key == "000" || key.isNumber == false)) {
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
value.append(key)
|
|
66
|
+
tempValue.append(convertedKey)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// MARK: Public
|
|
71
|
+
|
|
72
|
+
public var body: some View {
|
|
73
|
+
return GeometryReader { geo in
|
|
74
|
+
VStack {
|
|
75
|
+
HStack {
|
|
76
|
+
KeyboardButton("AC", action: self.onPressClear, color: Colors.pink07, textColor: Colors.black01)
|
|
77
|
+
KeyboardButton("÷", action: self.onPressKey, color: Colors.pink07, textColor: Colors.black01)
|
|
78
|
+
KeyboardButton("x", action: self.onPressKey, color: Colors.pink07, textColor: Colors.black01)
|
|
79
|
+
|
|
80
|
+
SwiftUI.Button(action: onPressBack) {
|
|
81
|
+
HStack {
|
|
82
|
+
Image(
|
|
83
|
+
systemName: "delete.backward"
|
|
84
|
+
).foregroundColor(Colors.black01)
|
|
85
|
+
}.frame(maxWidth: .infinity, minHeight: 48)
|
|
86
|
+
.background(Colors.pink07)
|
|
87
|
+
.foregroundColor(Colors.black01)
|
|
88
|
+
.clipShape(RoundedRectangle(cornerRadius: 8))
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
HStack {
|
|
93
|
+
KeyboardButton("7", action: self.onPressKey)
|
|
94
|
+
KeyboardButton("8", action: self.onPressKey)
|
|
95
|
+
KeyboardButton("9", action: self.onPressKey)
|
|
96
|
+
KeyboardButton("-", action: self.onPressKey, color: Colors.pink07, textColor: Colors.black01)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
HStack {
|
|
100
|
+
KeyboardButton("4", action: self.onPressKey)
|
|
101
|
+
KeyboardButton("5", action: self.onPressKey)
|
|
102
|
+
KeyboardButton("6", action: self.onPressKey)
|
|
103
|
+
KeyboardButton("+", action: self.onPressKey, color: Colors.pink07, textColor: Colors.black01)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
HStack{
|
|
107
|
+
VStack{
|
|
108
|
+
HStack {
|
|
109
|
+
KeyboardButton("1", action: self.onPressKey)
|
|
110
|
+
KeyboardButton("2", action: self.onPressKey)
|
|
111
|
+
KeyboardButton("3", action: self.onPressKey)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
HStack{
|
|
115
|
+
KeyboardButton("000", action: self.onPressKey)
|
|
116
|
+
KeyboardButton("0", action: self.onPressKey, width: CGFloat(geo.size.width * 0.25 - 5))
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
KeyboardButton("=", action: self.onPressEqual, width: CGFloat(geo.size.width * 0.25 - 5), height: 102, color: Colors.primary, textColor: Colors.black01)
|
|
121
|
+
|
|
122
|
+
}
|
|
123
|
+
}.background(Colors.background)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import SwiftUI
|
|
3
|
+
|
|
4
|
+
public struct Checkbox: View{
|
|
5
|
+
@Binding var checked: Bool
|
|
6
|
+
var disabled: Bool
|
|
7
|
+
var onChange: ((Bool)->Void)?
|
|
8
|
+
var indeterminate: Bool
|
|
9
|
+
var title: String
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
public init(_ checked: Binding<Bool>,disabled: Bool = false, onChange: ( (Bool) -> Void)? = nil,
|
|
13
|
+
indeterminate: Bool = false,
|
|
14
|
+
title: String = ""){
|
|
15
|
+
self._checked = checked
|
|
16
|
+
self.disabled = disabled
|
|
17
|
+
self.onChange = onChange
|
|
18
|
+
self.indeterminate = indeterminate
|
|
19
|
+
self.title = title
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
func onCheck(){
|
|
23
|
+
checked.toggle()
|
|
24
|
+
onChange?(checked)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public var body: some View {
|
|
28
|
+
HStack(spacing: Spacing.S) {
|
|
29
|
+
// Checkbox
|
|
30
|
+
ZStack {
|
|
31
|
+
RoundedRectangle(cornerRadius: Radius.XS)
|
|
32
|
+
.fill(backgroundColor)
|
|
33
|
+
.frame(width: 20, height: 20)
|
|
34
|
+
.overlay(
|
|
35
|
+
RoundedRectangle(cornerRadius: Radius.XS)
|
|
36
|
+
.stroke(borderColor, lineWidth: Spacing.XXS)
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
if checked {
|
|
40
|
+
Image(systemName: indeterminate ? "minus.square.fill" : "checkmark.square.fill")
|
|
41
|
+
.resizable()
|
|
42
|
+
.foregroundColor(backgroundColor)
|
|
43
|
+
.background(Colors.black01)
|
|
44
|
+
.frame(width: 20, height: 20)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.onTapGesture {
|
|
49
|
+
if !disabled {
|
|
50
|
+
onCheck()
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Title
|
|
55
|
+
if !title.isEmpty {
|
|
56
|
+
Text(title)
|
|
57
|
+
.font(.description1)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private var borderColor: Color {
|
|
63
|
+
if disabled {
|
|
64
|
+
return Colors.black03
|
|
65
|
+
} else if checked {
|
|
66
|
+
return Colors.primary
|
|
67
|
+
} else {
|
|
68
|
+
return Colors.text
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private var backgroundColor: Color {
|
|
73
|
+
if disabled && checked {
|
|
74
|
+
return Colors.pink08
|
|
75
|
+
} else if checked {
|
|
76
|
+
return Colors.primary
|
|
77
|
+
} else {
|
|
78
|
+
return Color.clear
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
import Foundation
|
|
3
|
+
|
|
4
|
+
public struct Chip: View {
|
|
5
|
+
public enum ChipSize { case small, large }
|
|
6
|
+
|
|
7
|
+
public struct Dimensions {
|
|
8
|
+
let horizontal: CGFloat
|
|
9
|
+
let vertical: CGFloat
|
|
10
|
+
let iconSize: CGFloat
|
|
11
|
+
let iconSpacing: CGFloat
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public static let Large = Dimensions(horizontal: 12, vertical: 8, iconSize: 20, iconSpacing: 8)
|
|
15
|
+
public static let Small = Dimensions(horizontal: 10, vertical: 6, iconSize: 16, iconSpacing: 6)
|
|
16
|
+
|
|
17
|
+
private let label: String?
|
|
18
|
+
private let iconLeft: String?
|
|
19
|
+
private let iconRight: String?
|
|
20
|
+
private let selected: Bool
|
|
21
|
+
private let onClick: () -> Void
|
|
22
|
+
private let size: ChipSize
|
|
23
|
+
private let iconLeftTint: Color?
|
|
24
|
+
private let iconRightTint: Color?
|
|
25
|
+
private let backgroundColor: Color?
|
|
26
|
+
private let accessibilityLabel: String?
|
|
27
|
+
|
|
28
|
+
public init(
|
|
29
|
+
label: String? = "Label",
|
|
30
|
+
iconLeft: String? = nil,
|
|
31
|
+
iconRight: String? = nil,
|
|
32
|
+
selected: Bool = false,
|
|
33
|
+
onClick: @escaping () -> Void = {},
|
|
34
|
+
size: ChipSize = .large,
|
|
35
|
+
iconLeftTint: Color? = nil,
|
|
36
|
+
iconRightTint: Color? = nil,
|
|
37
|
+
backgroundColor: Color? = nil,
|
|
38
|
+
accessibilityLabel: String? = nil
|
|
39
|
+
) {
|
|
40
|
+
self.label = label
|
|
41
|
+
self.iconLeft = iconLeft
|
|
42
|
+
self.iconRight = iconRight
|
|
43
|
+
self.selected = selected
|
|
44
|
+
self.onClick = onClick
|
|
45
|
+
self.size = size
|
|
46
|
+
self.iconLeftTint = iconLeftTint
|
|
47
|
+
self.iconRightTint = iconRightTint
|
|
48
|
+
self.backgroundColor = backgroundColor
|
|
49
|
+
self.accessibilityLabel = accessibilityLabel
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public var body: some View {
|
|
53
|
+
let dims = (size == .small) ? Self.Small : Self.Large
|
|
54
|
+
|
|
55
|
+
let bg: Color = {
|
|
56
|
+
if selected { return Colors.pink10 }
|
|
57
|
+
if let explicit = backgroundColor { return explicit }
|
|
58
|
+
return Colors.black03
|
|
59
|
+
}()
|
|
60
|
+
|
|
61
|
+
let textColor: Color = selected ? Colors.primary : Colors.text
|
|
62
|
+
let leftTint: Color = selected ? Colors.primary : iconLeftTint ?? Colors.text
|
|
63
|
+
let rightTint: Color = selected ? Colors.primary : iconRightTint ?? Colors.text
|
|
64
|
+
|
|
65
|
+
HStack(spacing: dims.iconSpacing) {
|
|
66
|
+
if let iconLeft {
|
|
67
|
+
Icon(source: iconLeft, size: dims.iconSize, color: leftTint)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if let text = label, !text.isEmpty {
|
|
71
|
+
MomoText(text, typography: (size == .large) ? .labelDefaultMedium : .labelSMedium, color: textColor)
|
|
72
|
+
.lineLimit(1)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if let iconRight {
|
|
76
|
+
Icon(source: iconRight, size: dims.iconSize, color: rightTint)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
.padding(.horizontal, dims.horizontal)
|
|
80
|
+
.padding(.vertical, dims.vertical)
|
|
81
|
+
.background(
|
|
82
|
+
RoundedRectangle(cornerRadius: Radius.L, style: .continuous)
|
|
83
|
+
.fill(bg)
|
|
84
|
+
)
|
|
85
|
+
.overlay(
|
|
86
|
+
Group {
|
|
87
|
+
if selected {
|
|
88
|
+
RoundedRectangle(cornerRadius: Radius.L, style: .continuous)
|
|
89
|
+
.stroke(Colors.primary, lineWidth: 2)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
)
|
|
93
|
+
.contentShape(RoundedRectangle(cornerRadius: Radius.L, style: .continuous))
|
|
94
|
+
.onTapGesture(perform: onClick)
|
|
95
|
+
}
|
|
96
|
+
}
|