@momo-kits/native-kits 0.0.1-beta.4 → 0.2.0-kt22
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/README.md +176 -5
- 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 +242 -0
- package/ios/Button/Button.swift +169 -89
- package/ios/CalculatorKeyboard/CalculatorKeyboard.swift +126 -0
- package/ios/Checkbox/Checkbox.swift +81 -0
- package/ios/Chip/Chip.swift +96 -0
- package/ios/{Colors+Spacing → Colors+Radius+Spacing}/Colors.swift +21 -19
- package/ios/Colors+Radius+Spacing/Radius.swift +22 -0
- package/ios/Icon/Icon.swift +51 -0
- package/ios/Image/Image.swift +70 -0
- package/ios/Input/ErrorView.swift +55 -0
- package/ios/Input/Input.swift +159 -50
- package/ios/Input/InputPhoneNumber.swift +158 -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 +12 -4
- package/ios/OTPKeyboard/OTPKeyboard.swift +1 -1
- package/ios/Popup/PopupDisplay.swift +287 -0
- package/ios/Popup/PopupInput.swift +96 -0
- package/ios/Popup/PopupPromotion.swift +73 -0
- package/ios/PopupView/FullscreenPopup.swift +251 -0
- package/ios/{Popup → PopupView}/Modifiers.swift +6 -20
- package/ios/{Popup → PopupView}/PopupView.swift +38 -146
- package/ios/PopupView/Utils++.swift +281 -0
- package/ios/ScrollIndicator/ScrollIndicator.swift +110 -0
- package/ios/Swipeable/SwipeCell.swift +39 -31
- 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/Typography/Text.swift +140 -0
- package/ios/Typography/Typography.swift +70 -5
- package/ios/native-kits.podspec +20 -15
- package/package.json +6 -6
- package/CODE_OF_CONDUCT.md +0 -133
- package/CONTRIBUTING.md +0 -114
- package/LICENSE +0 -20
- package/android/build.gradle +0 -82
- package/android/gradle.properties +0 -5
- package/android/src/main/AndroidManifest.xml +0 -4
- package/android/src/main/java/com/momoplatform/nativekits/NativeKitsPackage.kt +0 -17
- package/android/src/main/java/com/momoplatform/nativekits/NativeKitsViewManager.kt +0 -20
- package/example/ios/Example/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -63
- package/example/ios/Example/Assets.xcassets/Background.colorset/Contents.json +0 -38
- package/example/ios/Example/Assets.xcassets/Border.colorset/Contents.json +0 -38
- package/example/ios/Example/Assets.xcassets/Card.colorset/Contents.json +0 -38
- package/example/ios/Example/Assets.xcassets/Contents.json +0 -6
- package/example/ios/Example/Assets.xcassets/Error.colorset/Contents.json +0 -38
- package/example/ios/Example/Assets.xcassets/Primary.colorset/Contents.json +0 -38
- package/example/ios/Example/Assets.xcassets/PrimaryDark.colorset/Contents.json +0 -38
- package/example/ios/Example/Assets.xcassets/PrimaryLight.colorset/Contents.json +0 -38
- package/example/ios/Example/Assets.xcassets/Secondary.colorset/Contents.json +0 -38
- package/example/ios/Example/Assets.xcassets/Success.colorset/Contents.json +0 -38
- package/example/ios/Example/Assets.xcassets/Text.colorset/Contents.json +0 -38
- package/example/ios/Example/Assets.xcassets/TextSecondary.colorset/Contents.json +0 -38
- package/example/ios/Example/Assets.xcassets/Warning.colorset/Contents.json +0 -38
- package/example/ios/Example/ComponentDetail.swift +0 -35
- package/example/ios/Example/ComponentItem.swift +0 -24
- package/example/ios/Example/ComponentModel.swift +0 -33
- package/example/ios/Example/ContentView.swift +0 -53
- package/example/ios/Example/Example.entitlements +0 -10
- package/example/ios/Example/Foundation/ButtonDemo.swift +0 -80
- package/example/ios/Example/Foundation/Popup/ActionSheets.swift +0 -136
- package/example/ios/Example/Foundation/Popup/Floats.swift +0 -127
- package/example/ios/Example/Foundation/Popup/Popups.swift +0 -101
- package/example/ios/Example/Foundation/PopupDemo.swift +0 -366
- package/example/ios/Example/Foundation/TextInputDemo.swift +0 -31
- package/example/ios/Example/Foundation/TypographyDemo.swift +0 -53
- package/example/ios/Example/Foundation.swift +0 -26
- package/example/ios/Example/Info.plist +0 -18
- package/example/ios/Example/Library/SwipeableDemo.swift +0 -105
- package/example/ios/Example/Library.swift +0 -26
- package/example/ios/Example/Main.swift +0 -11
- package/example/ios/Example/Overview.swift +0 -20
- package/example/ios/Example/Preview Content/Preview Assets.xcassets/Contents.json +0 -6
- package/example/ios/Example/Resource/SFProText-Black.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Bold.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Heavy.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Light.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Medium.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Regular.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Semibold.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Thin.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Ultralight.ttf +0 -0
- package/example/ios/Example/Resource/foundation.json +0 -33
- package/example/ios/Example/Resource/library.json +0 -8
- package/example/ios/Example/Utils.swift +0 -30
- package/example/ios/Example/ViewModifier/DarkViewModifier.swift +0 -22
- package/example/ios/Example.xcodeproj/project.pbxproj +0 -570
- package/example/ios/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- package/example/ios/Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
- package/example/ios/Example.xcodeproj/project.xcworkspace/xcuserdata/wem.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/example/ios/Example.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
- package/example/ios/Example.xcworkspace/contents.xcworkspacedata +0 -10
- package/example/ios/Example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
- package/example/ios/Example.xcworkspace/xcuserdata/wem.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/example/ios/Example.xcworkspace/xcuserdata/wem.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +0 -6
- package/example/ios/Podfile +0 -6
- package/example/ios/Podfile.lock +0 -16
- package/example/ios/Pods/Local Podspecs/MoMoUIKits.podspec.json +0 -29
- package/example/ios/Pods/Manifest.lock +0 -16
- package/example/ios/Pods/Pods.xcodeproj/project.pbxproj +0 -661
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/MoMoUIKits.xcscheme +0 -58
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/Pods-Example.xcscheme +0 -58
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/xcschememanagement.plist +0 -25
- package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits-dummy.m +0 -5
- package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits-prefix.pch +0 -12
- package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits-umbrella.h +0 -16
- package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits.debug.xcconfig +0 -12
- package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits.modulemap +0 -6
- package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits.release.xcconfig +0 -12
- package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-acknowledgements.markdown +0 -3
- package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-acknowledgements.plist +0 -29
- package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-dummy.m +0 -5
- package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-umbrella.h +0 -16
- package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example.debug.xcconfig +0 -14
- package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example.modulemap +0 -6
- package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example.release.xcconfig +0 -14
- package/ios/Colors+Spacing/Radius.swift +0 -11
- package/ios/Popup/Utils++.swift +0 -163
- package/ios/Theme.md +0 -18
- package/publish.sh +0 -28
- /package/ios/{Colors+Spacing → Colors+Radius+Spacing}/Spacing.swift +0 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
|
|
3
|
+
// MARK: - Custom Shape for Rounded Corners
|
|
4
|
+
struct RoundedCorners: Shape {
|
|
5
|
+
var topLeft: CGFloat = 0.0
|
|
6
|
+
var topRight: CGFloat = 0.0
|
|
7
|
+
var bottomLeft: CGFloat = 0.0
|
|
8
|
+
var bottomRight: CGFloat = 0.0
|
|
9
|
+
|
|
10
|
+
func path(in rect: CGRect) -> Path {
|
|
11
|
+
var path = Path()
|
|
12
|
+
|
|
13
|
+
let width = rect.size.width
|
|
14
|
+
let height = rect.size.height
|
|
15
|
+
|
|
16
|
+
// Start from top left
|
|
17
|
+
path.move(to: CGPoint(x: topLeft, y: 0))
|
|
18
|
+
|
|
19
|
+
// Top edge and top right corner
|
|
20
|
+
path.addLine(to: CGPoint(x: width - topRight, y: 0))
|
|
21
|
+
if topRight > 0 {
|
|
22
|
+
path.addArc(
|
|
23
|
+
center: CGPoint(x: width - topRight, y: topRight),
|
|
24
|
+
radius: topRight,
|
|
25
|
+
startAngle: Angle(degrees: -90),
|
|
26
|
+
endAngle: Angle(degrees: 0),
|
|
27
|
+
clockwise: false
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Right edge and bottom right corner
|
|
32
|
+
path.addLine(to: CGPoint(x: width, y: height - bottomRight))
|
|
33
|
+
if bottomRight > 0 {
|
|
34
|
+
path.addArc(
|
|
35
|
+
center: CGPoint(x: width - bottomRight, y: height - bottomRight),
|
|
36
|
+
radius: bottomRight,
|
|
37
|
+
startAngle: Angle(degrees: 0),
|
|
38
|
+
endAngle: Angle(degrees: 90),
|
|
39
|
+
clockwise: false
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Bottom edge and bottom left corner
|
|
44
|
+
path.addLine(to: CGPoint(x: bottomLeft, y: height))
|
|
45
|
+
if bottomLeft > 0 {
|
|
46
|
+
path.addArc(
|
|
47
|
+
center: CGPoint(x: bottomLeft, y: height - bottomLeft),
|
|
48
|
+
radius: bottomLeft,
|
|
49
|
+
startAngle: Angle(degrees: 90),
|
|
50
|
+
endAngle: Angle(degrees: 180),
|
|
51
|
+
clockwise: false
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Left edge and top left corner
|
|
56
|
+
path.addLine(to: CGPoint(x: 0, y: topLeft))
|
|
57
|
+
if topLeft > 0 {
|
|
58
|
+
path.addArc(
|
|
59
|
+
center: CGPoint(x: topLeft, y: topLeft),
|
|
60
|
+
radius: topLeft,
|
|
61
|
+
startAngle: Angle(degrees: 180),
|
|
62
|
+
endAngle: Angle(degrees: 270),
|
|
63
|
+
clockwise: false
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
path.closeSubpath()
|
|
68
|
+
return path
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public enum RibbonPosition {
|
|
73
|
+
case topLeft
|
|
74
|
+
case topRight
|
|
75
|
+
case bottomLeft
|
|
76
|
+
case bottomRight
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public struct BadgeRibbon: View {
|
|
80
|
+
let position: RibbonPosition
|
|
81
|
+
let label: String
|
|
82
|
+
let isRound: Bool
|
|
83
|
+
let backgroundColor: Color
|
|
84
|
+
|
|
85
|
+
public init(
|
|
86
|
+
position: RibbonPosition = .topRight,
|
|
87
|
+
label: String = "Label",
|
|
88
|
+
isRound: Bool = false,
|
|
89
|
+
backgroundColor: Color? = nil
|
|
90
|
+
) {
|
|
91
|
+
self.position = position
|
|
92
|
+
self.label = label
|
|
93
|
+
self.isRound = isRound
|
|
94
|
+
self.backgroundColor = backgroundColor ?? Colors.orange03
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private var rotation: Angle {
|
|
98
|
+
switch position {
|
|
99
|
+
case .topRight, .bottomRight:
|
|
100
|
+
return .degrees(180)
|
|
101
|
+
case .topLeft, .bottomLeft:
|
|
102
|
+
return .zero
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
private var useUpTail: Bool {
|
|
107
|
+
position == .bottomLeft || position == .topRight
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private var verticalAlignment: VerticalAlignment {
|
|
111
|
+
switch position {
|
|
112
|
+
case .topLeft, .bottomRight:
|
|
113
|
+
return .top
|
|
114
|
+
case .bottomLeft, .topRight:
|
|
115
|
+
return .bottom
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
public var body: some View {
|
|
120
|
+
HStack(alignment: verticalAlignment, spacing: 0) {
|
|
121
|
+
if useUpTail {
|
|
122
|
+
upTail
|
|
123
|
+
} else {
|
|
124
|
+
downTail
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if isRound {
|
|
128
|
+
roundContent
|
|
129
|
+
} else {
|
|
130
|
+
skewContent
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
.frame(height: RibbonConstants.ribbonHeight)
|
|
134
|
+
.rotationEffect(rotation)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
private var roundContent: some View {
|
|
138
|
+
HStack(spacing: 0) {
|
|
139
|
+
Text(label)
|
|
140
|
+
.font(.system(size: 12, weight: .medium))
|
|
141
|
+
.foregroundColor(Colors.black01)
|
|
142
|
+
.lineLimit(1)
|
|
143
|
+
.rotationEffect(rotation)
|
|
144
|
+
}
|
|
145
|
+
.frame(height: RibbonConstants.roundHeight)
|
|
146
|
+
.padding(.trailing, RibbonConstants.roundPaddingEnd)
|
|
147
|
+
.background(
|
|
148
|
+
RoundedCorners(
|
|
149
|
+
topLeft: 0,
|
|
150
|
+
topRight: RibbonConstants.roundRightRadius,
|
|
151
|
+
bottomLeft: 0,
|
|
152
|
+
bottomRight: RibbonConstants.roundRightRadius
|
|
153
|
+
)
|
|
154
|
+
.fill(backgroundColor)
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
private var skewContent: some View {
|
|
159
|
+
HStack(spacing: 0) {
|
|
160
|
+
Text(label)
|
|
161
|
+
.font(.system(size: 12, weight: .medium))
|
|
162
|
+
.foregroundColor(Colors.black01)
|
|
163
|
+
.lineLimit(1)
|
|
164
|
+
.rotationEffect(rotation)
|
|
165
|
+
.frame(height: RibbonConstants.skewBodyHeight)
|
|
166
|
+
.padding(.horizontal, 8)
|
|
167
|
+
.background(backgroundColor)
|
|
168
|
+
|
|
169
|
+
rightTail
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
private var upTail: some View {
|
|
174
|
+
ImageView(
|
|
175
|
+
"https://static.momocdn.net/app/img/kits/utils/Head_down_4x.png",
|
|
176
|
+
placeholder: AnyView(Color.clear)
|
|
177
|
+
)
|
|
178
|
+
.frame(width: RibbonConstants.headTailWidth, height: RibbonConstants.headTailHeight)
|
|
179
|
+
.rotationEffect(.degrees(180))
|
|
180
|
+
.offset(x: 1)
|
|
181
|
+
.clipped()
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
private var downTail: some View {
|
|
185
|
+
ImageView(
|
|
186
|
+
"https://static.momocdn.net/app/img/kits/utils/Head_4x.png",
|
|
187
|
+
placeholder: AnyView(Color.clear)
|
|
188
|
+
)
|
|
189
|
+
.frame(width: RibbonConstants.headTailWidth, height: RibbonConstants.headTailHeight)
|
|
190
|
+
.offset(x: 1)
|
|
191
|
+
.clipped()
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
private var rightTail: some View {
|
|
195
|
+
ImageView(
|
|
196
|
+
"https://static.momocdn.net/app/img/kits/utils/Tail_4x.png",
|
|
197
|
+
placeholder: AnyView(Color.clear)
|
|
198
|
+
)
|
|
199
|
+
.frame(width: RibbonConstants.skewTailWidth, height: RibbonConstants.skewTailHeight)
|
|
200
|
+
.offset(x: -2)
|
|
201
|
+
.clipped()
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// MARK: - Constants
|
|
206
|
+
private struct RibbonConstants {
|
|
207
|
+
static let ribbonHeight: CGFloat = 20
|
|
208
|
+
static let roundHeight: CGFloat = 16
|
|
209
|
+
static let skewBodyHeight: CGFloat = 16
|
|
210
|
+
static let roundRightRadius: CGFloat = 8
|
|
211
|
+
static let roundPaddingEnd: CGFloat = 6
|
|
212
|
+
static let skewTailWidth: CGFloat = 8
|
|
213
|
+
static let skewTailHeight: CGFloat = 16
|
|
214
|
+
static let headTailWidth: CGFloat = 5
|
|
215
|
+
static let headTailHeight: CGFloat = 20
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// MARK: - String Extension for Text Size
|
|
219
|
+
extension String {
|
|
220
|
+
func size(withAttributes attributes: [NSAttributedString.Key: Any]?) -> CGSize {
|
|
221
|
+
let size = (self as NSString).size(withAttributes: attributes)
|
|
222
|
+
return size
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// MARK: - Preview
|
|
227
|
+
#if DEBUG
|
|
228
|
+
struct BadgeRibbon_Previews: PreviewProvider {
|
|
229
|
+
static var previews: some View {
|
|
230
|
+
VStack(spacing: 30) {
|
|
231
|
+
// Basic ribbon examples
|
|
232
|
+
BadgeRibbon(position: .topRight, label: "New")
|
|
233
|
+
BadgeRibbon(position: .topLeft, label: "Hot", isRound: true)
|
|
234
|
+
BadgeRibbon(position: .bottomLeft, label: "Sale")
|
|
235
|
+
BadgeRibbon(position: .bottomRight, label: "50% OFF", isRound: true)
|
|
236
|
+
}
|
|
237
|
+
.padding()
|
|
238
|
+
.previewLayout(.sizeThatFits)
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
#endif
|
|
242
|
+
|
package/ios/Button/Button.swift
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
|
|
2
1
|
import Foundation
|
|
2
|
+
import Lottie
|
|
3
3
|
import SwiftUI
|
|
4
4
|
|
|
5
5
|
// MARK: - ButtonType
|
|
6
6
|
|
|
7
7
|
public enum ButtonType {
|
|
8
8
|
case primary
|
|
9
|
-
case danger
|
|
10
|
-
case tonal
|
|
11
9
|
case secondary
|
|
10
|
+
case tonal
|
|
12
11
|
case outline
|
|
12
|
+
case danger
|
|
13
|
+
case text
|
|
13
14
|
case disabled
|
|
14
15
|
}
|
|
15
16
|
|
|
@@ -21,111 +22,190 @@ public enum ButtonSize {
|
|
|
21
22
|
case small
|
|
22
23
|
}
|
|
23
24
|
|
|
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
|
+
}
|
|
25
117
|
|
|
26
118
|
public struct Button: View {
|
|
27
|
-
|
|
119
|
+
var title: String
|
|
120
|
+
var action: () -> Void
|
|
121
|
+
var type: ButtonType
|
|
122
|
+
var size: ButtonSize
|
|
123
|
+
var iconLeft: AnyView?
|
|
124
|
+
var iconRight: AnyView?
|
|
125
|
+
var isFull: Bool
|
|
126
|
+
var loading: Bool
|
|
28
127
|
|
|
29
|
-
public init(
|
|
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
|
+
isFull: Bool = true,
|
|
136
|
+
loading: Bool = false
|
|
137
|
+
) {
|
|
30
138
|
self.title = title
|
|
31
139
|
self.action = action
|
|
32
140
|
self.type = type
|
|
33
141
|
self.size = size
|
|
34
142
|
self.iconLeft = iconLeft
|
|
35
143
|
self.iconRight = iconRight
|
|
144
|
+
self.isFull = isFull
|
|
145
|
+
self.loading = loading
|
|
36
146
|
}
|
|
37
147
|
|
|
38
|
-
|
|
148
|
+
private func shouldLoadingOnLeft(_ left: AnyView?, _ right: AnyView?) -> Bool {
|
|
149
|
+
let hasLeft = left != nil
|
|
150
|
+
let hasRight = right != nil
|
|
151
|
+
|
|
152
|
+
switch (hasLeft, hasRight) {
|
|
153
|
+
case (false, false): return true
|
|
154
|
+
case (true, false): return true
|
|
155
|
+
case (false, true): return false
|
|
156
|
+
case (true, true): return false
|
|
157
|
+
}
|
|
158
|
+
}
|
|
39
159
|
|
|
40
160
|
public var body: some View {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
161
|
+
let loadingOnLeft = shouldLoadingOnLeft(iconLeft, iconRight)
|
|
162
|
+
|
|
163
|
+
let bg = type.backgroundColor(loading: loading)
|
|
164
|
+
let fg = type.contentColor(loading: loading)
|
|
165
|
+
let border = type.borderColor
|
|
166
|
+
let borderWidth = type.borderWidth
|
|
167
|
+
|
|
168
|
+
SwiftUI.Button(action: {
|
|
169
|
+
if !loading, type != .disabled {
|
|
170
|
+
action()
|
|
46
171
|
}
|
|
47
|
-
|
|
48
|
-
.
|
|
49
|
-
|
|
50
|
-
|
|
172
|
+
}) {
|
|
173
|
+
HStack(spacing: size.iconSpacing) {
|
|
174
|
+
if loading && loadingOnLeft {
|
|
175
|
+
LottieView(name: "lottie_circle_loader", loopMode: .loop)
|
|
176
|
+
.frame(width: size.iconSize, height: size.iconSize)
|
|
177
|
+
.colorMultiply(fg)
|
|
51
178
|
|
|
52
|
-
|
|
179
|
+
} else if let iconLeft = iconLeft {
|
|
180
|
+
iconLeft.frame(width: size.iconSize, height: size.iconSize)
|
|
181
|
+
}
|
|
53
182
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
var iconRight: AnyView?
|
|
183
|
+
Text(title)
|
|
184
|
+
.font(size.font)
|
|
185
|
+
.foregroundColor(fg)
|
|
186
|
+
.lineLimit(1)
|
|
187
|
+
.truncationMode(.tail)
|
|
60
188
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
case .medium:
|
|
66
|
-
return Text(title).font(.system(size: 14, weight: Font.Weight.bold))
|
|
67
|
-
case .small:
|
|
68
|
-
return Text(title).font(.system(size: 12, weight: Font.Weight.bold))
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
189
|
+
if loading && !loadingOnLeft {
|
|
190
|
+
LottieView(name: "lottie_circle_loader", loopMode: .loop)
|
|
191
|
+
.frame(width: size.iconSize, height: size.iconSize)
|
|
192
|
+
.colorMultiply(fg)
|
|
72
193
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
.foregroundColor(Colors.black01)
|
|
85
|
-
.clipShape(RoundedRectangle(cornerRadius: Radius.S)))
|
|
86
|
-
case .tonal:
|
|
87
|
-
return AnyView(self
|
|
88
|
-
.background(Colors.primaryLight)
|
|
89
|
-
.foregroundColor(Colors.primary)
|
|
90
|
-
.clipShape(RoundedRectangle(cornerRadius: Radius.S)))
|
|
91
|
-
case .secondary:
|
|
92
|
-
return AnyView(self
|
|
93
|
-
.background(Colors.card)
|
|
94
|
-
.foregroundColor(Colors.text)
|
|
95
|
-
.cornerRadius(8)
|
|
96
|
-
.overlay(RoundedRectangle(cornerRadius: Radius.S).stroke(Colors.black06, lineWidth: 1))
|
|
97
|
-
.padding(2)
|
|
98
|
-
)
|
|
99
|
-
case .outline:
|
|
100
|
-
return AnyView(self
|
|
101
|
-
.background(Colors.card)
|
|
102
|
-
.foregroundColor(Colors.primary)
|
|
103
|
-
.cornerRadius(8)
|
|
104
|
-
.overlay(RoundedRectangle(cornerRadius: Radius.S).stroke(Colors.primary, lineWidth: 1))
|
|
105
|
-
.padding(2)
|
|
194
|
+
} else if let iconRight = iconRight {
|
|
195
|
+
iconRight.frame(width: size.iconSize, height: size.iconSize)
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
.frame(maxWidth: isFull ? .infinity : nil)
|
|
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)
|
|
106
205
|
)
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
.background(Colors.black05)
|
|
110
|
-
.foregroundColor(Colors.black06)
|
|
111
|
-
.clipShape(RoundedRectangle(cornerRadius: Radius.S)))
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
func buttonSize(_ size: ButtonSize) -> some View {
|
|
116
|
-
switch size {
|
|
117
|
-
case .large:
|
|
118
|
-
return self
|
|
119
|
-
.frame(maxWidth: .infinity, minHeight: 48, maxHeight: 48)
|
|
120
|
-
.padding([.leading, .trailing], Spacing.XS)
|
|
121
|
-
case .medium:
|
|
122
|
-
return self
|
|
123
|
-
.frame(minWidth: 80, maxWidth: 96, minHeight: 36, maxHeight: 36)
|
|
124
|
-
.padding([.leading, .trailing], Spacing.XS)
|
|
125
|
-
case .small:
|
|
126
|
-
return self
|
|
127
|
-
.frame(minWidth: 56, maxWidth: 76, minHeight: 28, maxHeight: 28)
|
|
128
|
-
.padding([.leading, .trailing], Spacing.XS)
|
|
206
|
+
.clipShape(RoundedRectangle(cornerRadius: size.radius))
|
|
207
|
+
.opacity(loading ? 0.75 : 1)
|
|
129
208
|
}
|
|
209
|
+
.disabled(type == .disabled || loading)
|
|
130
210
|
}
|
|
131
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
|
+
}
|