@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.
Files changed (131) hide show
  1. package/README.md +176 -5
  2. package/ios/Application/ApplicationEnvironment.swift +50 -0
  3. package/ios/Application/Components.swift +263 -0
  4. package/ios/Application/ComposeApi.swift +22 -0
  5. package/ios/Application/FloatingButton.swift +172 -0
  6. package/ios/Application/HeaderRight.swift +271 -0
  7. package/ios/Application/Screen.swift +249 -0
  8. package/ios/Badge/Badge.swift +85 -0
  9. package/ios/Badge/BadgeDot.swift +31 -0
  10. package/ios/Badge/BadgeRibbon.swift +242 -0
  11. package/ios/Button/Button.swift +169 -89
  12. package/ios/CalculatorKeyboard/CalculatorKeyboard.swift +126 -0
  13. package/ios/Checkbox/Checkbox.swift +81 -0
  14. package/ios/Chip/Chip.swift +96 -0
  15. package/ios/{Colors+Spacing → Colors+Radius+Spacing}/Colors.swift +21 -19
  16. package/ios/Colors+Radius+Spacing/Radius.swift +22 -0
  17. package/ios/Icon/Icon.swift +51 -0
  18. package/ios/Image/Image.swift +70 -0
  19. package/ios/Input/ErrorView.swift +55 -0
  20. package/ios/Input/Input.swift +159 -50
  21. package/ios/Input/InputPhoneNumber.swift +158 -0
  22. package/ios/Input/InputSearch.swift +238 -0
  23. package/ios/Input/InputTextArea.swift +242 -0
  24. package/ios/Lottie/LottieView.swift +86 -0
  25. package/ios/OTPKeyboard/KeyboardButton.swift +12 -4
  26. package/ios/OTPKeyboard/OTPKeyboard.swift +1 -1
  27. package/ios/Popup/PopupDisplay.swift +287 -0
  28. package/ios/Popup/PopupInput.swift +96 -0
  29. package/ios/Popup/PopupPromotion.swift +73 -0
  30. package/ios/PopupView/FullscreenPopup.swift +251 -0
  31. package/ios/{Popup → PopupView}/Modifiers.swift +6 -20
  32. package/ios/{Popup → PopupView}/PopupView.swift +38 -146
  33. package/ios/PopupView/Utils++.swift +281 -0
  34. package/ios/ScrollIndicator/ScrollIndicator.swift +110 -0
  35. package/ios/Swipeable/SwipeCell.swift +39 -31
  36. package/ios/Switch/Switch.swift +44 -0
  37. package/ios/Template/Logo/Logo.swift +75 -0
  38. package/ios/Template/TrustBanner/TrustBanner.swift +120 -0
  39. package/ios/Typography/Text.swift +140 -0
  40. package/ios/Typography/Typography.swift +70 -5
  41. package/ios/native-kits.podspec +20 -15
  42. package/package.json +6 -6
  43. package/CODE_OF_CONDUCT.md +0 -133
  44. package/CONTRIBUTING.md +0 -114
  45. package/LICENSE +0 -20
  46. package/android/build.gradle +0 -82
  47. package/android/gradle.properties +0 -5
  48. package/android/src/main/AndroidManifest.xml +0 -4
  49. package/android/src/main/java/com/momoplatform/nativekits/NativeKitsPackage.kt +0 -17
  50. package/android/src/main/java/com/momoplatform/nativekits/NativeKitsViewManager.kt +0 -20
  51. package/example/ios/Example/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -63
  52. package/example/ios/Example/Assets.xcassets/Background.colorset/Contents.json +0 -38
  53. package/example/ios/Example/Assets.xcassets/Border.colorset/Contents.json +0 -38
  54. package/example/ios/Example/Assets.xcassets/Card.colorset/Contents.json +0 -38
  55. package/example/ios/Example/Assets.xcassets/Contents.json +0 -6
  56. package/example/ios/Example/Assets.xcassets/Error.colorset/Contents.json +0 -38
  57. package/example/ios/Example/Assets.xcassets/Primary.colorset/Contents.json +0 -38
  58. package/example/ios/Example/Assets.xcassets/PrimaryDark.colorset/Contents.json +0 -38
  59. package/example/ios/Example/Assets.xcassets/PrimaryLight.colorset/Contents.json +0 -38
  60. package/example/ios/Example/Assets.xcassets/Secondary.colorset/Contents.json +0 -38
  61. package/example/ios/Example/Assets.xcassets/Success.colorset/Contents.json +0 -38
  62. package/example/ios/Example/Assets.xcassets/Text.colorset/Contents.json +0 -38
  63. package/example/ios/Example/Assets.xcassets/TextSecondary.colorset/Contents.json +0 -38
  64. package/example/ios/Example/Assets.xcassets/Warning.colorset/Contents.json +0 -38
  65. package/example/ios/Example/ComponentDetail.swift +0 -35
  66. package/example/ios/Example/ComponentItem.swift +0 -24
  67. package/example/ios/Example/ComponentModel.swift +0 -33
  68. package/example/ios/Example/ContentView.swift +0 -53
  69. package/example/ios/Example/Example.entitlements +0 -10
  70. package/example/ios/Example/Foundation/ButtonDemo.swift +0 -80
  71. package/example/ios/Example/Foundation/Popup/ActionSheets.swift +0 -136
  72. package/example/ios/Example/Foundation/Popup/Floats.swift +0 -127
  73. package/example/ios/Example/Foundation/Popup/Popups.swift +0 -101
  74. package/example/ios/Example/Foundation/PopupDemo.swift +0 -366
  75. package/example/ios/Example/Foundation/TextInputDemo.swift +0 -31
  76. package/example/ios/Example/Foundation/TypographyDemo.swift +0 -53
  77. package/example/ios/Example/Foundation.swift +0 -26
  78. package/example/ios/Example/Info.plist +0 -18
  79. package/example/ios/Example/Library/SwipeableDemo.swift +0 -105
  80. package/example/ios/Example/Library.swift +0 -26
  81. package/example/ios/Example/Main.swift +0 -11
  82. package/example/ios/Example/Overview.swift +0 -20
  83. package/example/ios/Example/Preview Content/Preview Assets.xcassets/Contents.json +0 -6
  84. package/example/ios/Example/Resource/SFProText-Black.ttf +0 -0
  85. package/example/ios/Example/Resource/SFProText-Bold.ttf +0 -0
  86. package/example/ios/Example/Resource/SFProText-Heavy.ttf +0 -0
  87. package/example/ios/Example/Resource/SFProText-Light.ttf +0 -0
  88. package/example/ios/Example/Resource/SFProText-Medium.ttf +0 -0
  89. package/example/ios/Example/Resource/SFProText-Regular.ttf +0 -0
  90. package/example/ios/Example/Resource/SFProText-Semibold.ttf +0 -0
  91. package/example/ios/Example/Resource/SFProText-Thin.ttf +0 -0
  92. package/example/ios/Example/Resource/SFProText-Ultralight.ttf +0 -0
  93. package/example/ios/Example/Resource/foundation.json +0 -33
  94. package/example/ios/Example/Resource/library.json +0 -8
  95. package/example/ios/Example/Utils.swift +0 -30
  96. package/example/ios/Example/ViewModifier/DarkViewModifier.swift +0 -22
  97. package/example/ios/Example.xcodeproj/project.pbxproj +0 -570
  98. package/example/ios/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  99. package/example/ios/Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  100. package/example/ios/Example.xcodeproj/project.xcworkspace/xcuserdata/wem.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  101. package/example/ios/Example.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
  102. package/example/ios/Example.xcworkspace/contents.xcworkspacedata +0 -10
  103. package/example/ios/Example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  104. package/example/ios/Example.xcworkspace/xcuserdata/wem.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  105. package/example/ios/Example.xcworkspace/xcuserdata/wem.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +0 -6
  106. package/example/ios/Podfile +0 -6
  107. package/example/ios/Podfile.lock +0 -16
  108. package/example/ios/Pods/Local Podspecs/MoMoUIKits.podspec.json +0 -29
  109. package/example/ios/Pods/Manifest.lock +0 -16
  110. package/example/ios/Pods/Pods.xcodeproj/project.pbxproj +0 -661
  111. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/MoMoUIKits.xcscheme +0 -58
  112. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/Pods-Example.xcscheme +0 -58
  113. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/xcschememanagement.plist +0 -25
  114. package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits-dummy.m +0 -5
  115. package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits-prefix.pch +0 -12
  116. package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits-umbrella.h +0 -16
  117. package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits.debug.xcconfig +0 -12
  118. package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits.modulemap +0 -6
  119. package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits.release.xcconfig +0 -12
  120. package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-acknowledgements.markdown +0 -3
  121. package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-acknowledgements.plist +0 -29
  122. package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-dummy.m +0 -5
  123. package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-umbrella.h +0 -16
  124. package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example.debug.xcconfig +0 -14
  125. package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example.modulemap +0 -6
  126. package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example.release.xcconfig +0 -14
  127. package/ios/Colors+Spacing/Radius.swift +0 -11
  128. package/ios/Popup/Utils++.swift +0 -163
  129. package/ios/Theme.md +0 -18
  130. package/publish.sh +0 -28
  131. /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
+
@@ -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
- // MARK: - Button
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
- // MARK: Lifecycle
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(title: String = "", action: @escaping () -> Void, type: ButtonType = .primary, size: ButtonSize = .large, iconLeft: AnyView? = nil, iconRight: AnyView? = nil) {
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
- // MARK: Public
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
- SwiftUI.Button(action: action) {
42
- HStack {
43
- iconLeft
44
- renderTitle(title: title, type: type, size: size)
45
- iconRight
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
- .buttonSize(size)
48
- .buttonType(type)
49
- }.disabled(type == .disabled)
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
- // MARK: Internal
179
+ } else if let iconLeft = iconLeft {
180
+ iconLeft.frame(width: size.iconSize, height: size.iconSize)
181
+ }
53
182
 
54
- var title: String
55
- var action: () -> Void = {}
56
- var type: ButtonType = .primary
57
- var size: ButtonSize = .large
58
- var iconLeft: AnyView?
59
- var iconRight: AnyView?
183
+ Text(title)
184
+ .font(size.font)
185
+ .foregroundColor(fg)
186
+ .lineLimit(1)
187
+ .truncationMode(.tail)
60
188
 
61
- func renderTitle(title: String, type: ButtonType, size: ButtonSize) -> Text {
62
- switch size {
63
- case .large:
64
- return Text(title).font(.system(size: 16, weight: Font.Weight.bold))
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
- private extension View {
74
- func buttonType(_ type: ButtonType) -> some View {
75
- switch type {
76
- case .primary:
77
- return AnyView(self
78
- .background(Colors.primary)
79
- .foregroundColor(Colors.black01)
80
- .clipShape(RoundedRectangle(cornerRadius: Radius.S)))
81
- case .danger:
82
- return AnyView(self
83
- .background(Colors.error)
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
- case .disabled:
108
- return AnyView(self
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
+ }