@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.
Files changed (157) hide show
  1. package/CODE_OF_CONDUCT.md +133 -0
  2. package/CONTRIBUTING.md +114 -0
  3. package/LICENSE +20 -0
  4. package/README.md +7 -0
  5. package/build.gradle.kts +32 -0
  6. package/compose/MoMoComposeKits.podspec +54 -0
  7. package/compose/build.gradle.kts +149 -0
  8. package/compose/src/androidMain/AndroidManifest.xml +2 -0
  9. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +105 -0
  10. package/compose/src/commonMain/composeResources/files/lottie_circle_loader.json +1 -0
  11. package/compose/src/commonMain/composeResources/font/momosignature.otf +0 -0
  12. package/compose/src/commonMain/composeResources/font/momotrustdisplay.otf +0 -0
  13. package/compose/src/commonMain/composeResources/font/sfprotext_black.otf +0 -0
  14. package/compose/src/commonMain/composeResources/font/sfprotext_black.ttf +0 -0
  15. package/compose/src/commonMain/composeResources/font/sfprotext_bold.ttf +0 -0
  16. package/compose/src/commonMain/composeResources/font/sfprotext_heavy.ttf +0 -0
  17. package/compose/src/commonMain/composeResources/font/sfprotext_light.ttf +0 -0
  18. package/compose/src/commonMain/composeResources/font/sfprotext_medium.ttf +0 -0
  19. package/compose/src/commonMain/composeResources/font/sfprotext_regular.ttf +0 -0
  20. package/compose/src/commonMain/composeResources/font/sfprotext_semibold.ttf +0 -0
  21. package/compose/src/commonMain/composeResources/font/sfprotext_thin.otf +0 -0
  22. package/compose/src/commonMain/composeResources/font/sfprotext_thin.ttf +0 -0
  23. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.otf +0 -0
  24. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.ttf +0 -0
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +57 -0
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +201 -0
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +222 -0
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +48 -0
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +86 -0
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +76 -0
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +76 -0
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +306 -0
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +33 -0
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +715 -0
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +214 -0
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +236 -0
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +69 -0
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +77 -0
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +27 -0
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +334 -0
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +345 -0
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +90 -0
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +131 -0
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +543 -0
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +23 -0
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +58 -0
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +143 -0
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +179 -0
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +111 -0
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +384 -0
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +160 -0
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +234 -0
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +223 -0
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +232 -0
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +236 -0
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +228 -0
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +364 -0
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +50 -0
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +34 -0
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +85 -0
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +33 -0
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +338 -0
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +95 -0
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +64 -0
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +89 -0
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +91 -0
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +86 -0
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +84 -0
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +208 -0
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +172 -0
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +199 -0
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +29 -0
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +237 -0
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +191 -0
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +306 -0
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +12 -0
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +13 -0
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +191 -0
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +258 -0
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +2 -0
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +35 -0
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +2 -0
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +59 -0
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +68 -0
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +11 -0
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +49 -0
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +51 -0
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +232 -0
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +111 -0
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +94 -0
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +159 -0
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +232 -0
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScaleSizeScope.kt +17 -0
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +459 -0
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +169 -0
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +216 -0
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +86 -0
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +180 -0
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +251 -0
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +80 -0
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +306 -0
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +31 -0
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +385 -0
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +38 -0
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +1329 -0
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +62 -0
  107. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +88 -0
  108. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +144 -0
  109. package/gradle.properties +19 -0
  110. package/gradlew +240 -0
  111. package/gradlew.bat +91 -0
  112. package/ios/Application/ApplicationEnvironment.swift +50 -0
  113. package/ios/Application/Components.swift +263 -0
  114. package/ios/Application/ComposeApi.swift +22 -0
  115. package/ios/Application/FloatingButton.swift +172 -0
  116. package/ios/Application/HeaderRight.swift +271 -0
  117. package/ios/Application/Screen.swift +249 -0
  118. package/ios/Badge/Badge.swift +85 -0
  119. package/ios/Badge/BadgeDot.swift +31 -0
  120. package/ios/Badge/BadgeRibbon.swift +174 -0
  121. package/ios/Button/Button.swift +211 -0
  122. package/ios/CalculatorKeyboard/CalculatorKeyboard.swift +126 -0
  123. package/ios/Checkbox/Checkbox.swift +81 -0
  124. package/ios/Chip/Chip.swift +96 -0
  125. package/ios/Colors+Radius+Spacing/Colors.swift +172 -0
  126. package/ios/Colors+Radius+Spacing/Radius.swift +22 -0
  127. package/ios/Colors+Radius+Spacing/Spacing.swift +12 -0
  128. package/ios/Extensions/Color++.swift +25 -0
  129. package/ios/Icon/Icon.swift +51 -0
  130. package/ios/Image/Image.swift +70 -0
  131. package/ios/Input/Input.swift +207 -0
  132. package/ios/Input/InputPhoneNumber.swift +176 -0
  133. package/ios/Input/InputSearch.swift +238 -0
  134. package/ios/Input/InputTextArea.swift +242 -0
  135. package/ios/Lottie/LottieView.swift +86 -0
  136. package/ios/OTPKeyboard/KeyboardButton.swift +41 -0
  137. package/ios/OTPKeyboard/OTPKeyboard.swift +145 -0
  138. package/ios/Popup/PopupDisplay.swift +284 -0
  139. package/ios/Popup/PopupInput.swift +96 -0
  140. package/ios/Popup/PopupPromotion.swift +73 -0
  141. package/ios/PopupView/FullscreenPopup.swift +251 -0
  142. package/ios/PopupView/Modifiers.swift +158 -0
  143. package/ios/PopupView/PopupView.swift +289 -0
  144. package/ios/PopupView/Utils++.swift +281 -0
  145. package/ios/ScrollIndicator/ScrollIndicator.swift +110 -0
  146. package/ios/Swipeable/SwipeCell.swift +278 -0
  147. package/ios/Swipeable/SwipeCellModel.swift +86 -0
  148. package/ios/Switch/Switch.swift +44 -0
  149. package/ios/Template/Logo/Logo.swift +75 -0
  150. package/ios/Template/TrustBanner/TrustBanner.swift +120 -0
  151. package/ios/Theme.md +18 -0
  152. package/ios/Typography/Text.swift +140 -0
  153. package/ios/Typography/Typography.swift +95 -0
  154. package/ios/native-kits.podspec +18 -0
  155. package/package.json +6 -7
  156. package/settings.gradle.kts +25 -0
  157. 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
+ }