@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,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
+ }
@@ -16,27 +16,28 @@ public enum Colors {
16
16
  public static let info = Color("Info")
17
17
  public static let success = Color("Success")
18
18
 
19
- public static let black20 = Color(hex: "08101d")
20
- public static let black19 = Color(hex: "0f1c2f")
21
- public static let black18 = Color(hex: "1c293d")
22
- public static let black17 = Color(hex: "2b3748")
23
- public static let black16 = Color(hex: "3a4454")
24
- public static let black15 = Color(hex: "475160")
25
- public static let black14 = Color(hex: "555e6c")
26
- public static let black13 = Color(hex: "636b78")
27
- public static let black12 = Color(hex: "6f7682")
28
- public static let black11 = Color(hex: "7e8590")
29
- public static let black10 = Color(hex: "8c929c")
30
- public static let black09 = Color(hex: "9a9fa8")
31
- public static let black08 = Color(hex: "a8adb4")
32
- public static let black07 = Color(hex: "b5bac0")
33
- public static let black06 = Color(hex: "c8cbcf")
34
- public static let black05 = Color(hex: "e0e1e4")
35
- public static let black04 = Color(hex: "ececee")
36
- public static let black03 = Color(hex: "f4f5f6")
37
- public static let black02 = Color(hex: "fafbfc")
19
+ public static let black20 = Color(hex: "000000")
20
+ public static let black19 = Color(hex: "18191a")
21
+ public static let black18 = Color(hex: "242424")
22
+ public static let black17 = Color(hex: "303233")
23
+ public static let black16 = Color(hex: "404040")
24
+ public static let black15 = Color(hex: "484848")
25
+ public static let black14 = Color(hex: "565656")
26
+ public static let black13 = Color(hex: "646464")
27
+ public static let black12 = Color(hex: "727272")
28
+ public static let black11 = Color(hex: "878787")
29
+ public static let black10 = Color(hex: "a0a0a0")
30
+ public static let black09 = Color(hex: "b9b9b9")
31
+ public static let black08 = Color(hex: "c6c6c6")
32
+ public static let black07 = Color(hex: "cccccc")
33
+ public static let black06 = Color(hex: "d8d8d8")
34
+ public static let black05 = Color(hex: "e5e5e5")
35
+ public static let black04 = Color(hex: "e8e8e8")
36
+ public static let black03 = Color(hex: "f0f0f0")
37
+ public static let black02 = Color(hex: "f9f9f9")
38
38
  public static let black01 = Color(hex: "ffffff")
39
39
 
40
+
40
41
  public static let pink11 = Color(hex: "fef8fc")
41
42
  public static let pink10 = Color(hex: "fef4fa")
42
43
  public static let pink09 = Color(hex: "fdeaf4")
@@ -49,6 +50,7 @@ public enum Colors {
49
50
  public static let pink02 = Color(hex: "d42a87")
50
51
  public static let pink01 = Color(hex: "bc2678")
51
52
 
53
+
52
54
  public static let violet10 = Color(hex: "fcf8fe")
53
55
  public static let violet09 = Color(hex: "faf4fe")
54
56
  public static let violet08 = Color(hex: "ead4fc")
@@ -0,0 +1,22 @@
1
+ import SwiftUI
2
+ import Foundation
3
+
4
+ public enum Radius {
5
+ public static let XXS: CGFloat = 2
6
+ public static let XS: CGFloat = 4
7
+ public static let S: CGFloat = 8
8
+ public static let M: CGFloat = 12
9
+ public static let L: CGFloat = 16
10
+ public static let XL: CGFloat = 24
11
+ }
12
+
13
+ public struct RoundedCorner: Shape {
14
+
15
+ var radius: CGFloat = .infinity
16
+ var corners: UIRectCorner = .allCorners
17
+
18
+ public func path(in rect: CGRect) -> Path {
19
+ let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
20
+ return Path(path.cgPath)
21
+ }
22
+ }
@@ -0,0 +1,51 @@
1
+ import SwiftUI
2
+
3
+ struct IconSource: Codable {
4
+ let uri: String
5
+ }
6
+
7
+ func loadIconSources() -> [String: IconSource] {
8
+ guard let url = Bundle.main.url(forResource: "icon", withExtension: "json") else {
9
+ print("Error: icon.json not found")
10
+ return [:]
11
+ }
12
+
13
+ do {
14
+ let data = try Data(contentsOf: url)
15
+ let decoded = try JSONDecoder().decode([String: IconSource].self, from: data)
16
+ return decoded
17
+ } catch {
18
+ print("Error decoding icon.json: \(error)")
19
+ return [:]
20
+ }
21
+ }
22
+
23
+ // Load the JSON data into a global variable
24
+ let iconSources: [String: IconSource] = loadIconSources()
25
+
26
+ // Icon ViewModel
27
+ public struct Icon: View {
28
+ var source: String
29
+ var size: CGFloat
30
+ var color: Color?
31
+ var accessibilityLabel: String?
32
+
33
+ public init(
34
+ source: String,
35
+ size: CGFloat = 24,
36
+ color: Color? = nil,
37
+ accessibilityLabel: String? = nil
38
+ ) {
39
+ self.source = source
40
+ self.size = size
41
+ self.color = color
42
+ self.accessibilityLabel = accessibilityLabel
43
+ }
44
+
45
+ public var body: some View {
46
+ if let uri = iconSources[source]?.uri {
47
+ ImageView(uri, color: color).frame(width: size, height: size)
48
+ }
49
+ }
50
+ }
51
+
@@ -0,0 +1,70 @@
1
+
2
+
3
+ import Foundation
4
+ import SDWebImageSwiftUI
5
+ import SkeletonUI
6
+ import SwiftUI
7
+
8
+ public struct ImageView: View {
9
+ // MARK: Lifecycle
10
+
11
+ public init(_ url: String, aspectRatio: CGFloat? = nil, contentMode: ContentMode = ContentMode.fit, placeholder: AnyView? = nil, color: Color? = nil) {
12
+ self.url = url
13
+ self.aspectRatio = aspectRatio
14
+ self.contentMode = contentMode
15
+ self.placeholder = placeholder
16
+ self.color = color
17
+ }
18
+
19
+ // MARK: Public
20
+
21
+ public var body: some View {
22
+ return WebImage(url: URL(string: url), isAnimating: .constant(true))
23
+ .onFailure { _ in
24
+ error = true
25
+ }
26
+ .onSuccess { _, _, _ in
27
+ error = false
28
+ }
29
+ .resizable()
30
+ .renderingMode(color != nil ? .template : .original)
31
+ .placeholder {
32
+ VStack(alignment: .center, content: {
33
+ if error {
34
+ Image(systemName: "photo.badge.exclamationmark").frame(width: 24, height: 24)
35
+ } else if placeholder != nil {
36
+ placeholder
37
+ }
38
+ })
39
+ .frame(maxWidth: .infinity, maxHeight: .infinity)
40
+ .skeleton(with: !error && placeholder == nil)
41
+ .shape(type: .rectangle)
42
+ }
43
+ .scaledToFit()
44
+ .transition(.fade)
45
+ .aspectRatio(aspectRatio, contentMode: contentMode)
46
+ .foregroundColor(color)
47
+ }
48
+
49
+ // MARK: Internal
50
+
51
+ var aspectRatio: CGFloat?
52
+ var contentMode: ContentMode
53
+ var placeholder: AnyView?
54
+ var color: Color?
55
+
56
+ @State var error: Bool = false
57
+ var url: String
58
+ }
59
+
60
+ private struct ColorMultiplyModifier: ViewModifier {
61
+ let color: Color?
62
+
63
+ func body(content: Content) -> some View {
64
+ if let color {
65
+ content.colorMultiply(color)
66
+ } else {
67
+ content
68
+ }
69
+ }
70
+ }
@@ -0,0 +1,55 @@
1
+ //
2
+ // ErrorView.swift
3
+ // Pods
4
+ //
5
+ // Created by sophia on 13/1/26.
6
+ //
7
+
8
+ import SwiftUI
9
+
10
+ public struct ErrorView: View {
11
+ public var errorMessage: String
12
+ public var errorSpacing: Bool
13
+ public var hintText: String
14
+
15
+ public init(
16
+ errorMessage: String = "",
17
+ errorSpacing: Bool = false,
18
+ hintText: String = ""
19
+ ) {
20
+ self.errorMessage = errorMessage
21
+ self.errorSpacing = errorSpacing
22
+ self.hintText = hintText
23
+ }
24
+
25
+ public var body: some View {
26
+ if !errorMessage.isEmpty || !hintText.isEmpty {
27
+ HStack(alignment: .top, spacing: 4) {
28
+ Icon(source: "ic_error", size: scaleSize(16), color: displayColor())
29
+ MomoText(
30
+ displayText(),
31
+ typography: .descriptionDefaultRegular,
32
+ color: displayColor()
33
+ )
34
+ }
35
+ .padding(.top, Spacing.XS)
36
+ } else if errorSpacing {
37
+ Spacer()
38
+ .padding(.top, Spacing.XS)
39
+ .frame(height: 18)
40
+ }
41
+ }
42
+
43
+ // MARK: - Helpers
44
+
45
+ private func displayColor() -> Color {
46
+ !errorMessage.isEmpty ? Colors.red03 : Colors.black12
47
+ }
48
+
49
+ private func displayText() -> String {
50
+ if !errorMessage.isEmpty {
51
+ return errorMessage
52
+ }
53
+ return hintText.isEmpty ? "Không thể chỉnh sửa" : hintText
54
+ }
55
+ }
@@ -4,22 +4,22 @@ import SwiftUI
4
4
 
5
5
  fileprivate struct FloatingComponent: View {
6
6
  var floatingValue: String
7
+ var floatingIcon: AnyView?
7
8
 
8
- public init (_ floatingValue: String = ""){
9
+ public init (_ floatingValue: String = "", floatingIcon: AnyView? = nil){
9
10
  self.floatingValue = floatingValue
11
+ self.floatingIcon = floatingIcon
10
12
  }
11
13
 
12
14
  public var body: some View {
13
15
  return HStack {
14
16
  Text(floatingValue)
17
+ .font(.paragraph)
15
18
  .foregroundColor(Colors.black09)
16
19
  .font(.system(size: 12))
17
20
  .padding(.leading, 8)
18
- Image(systemName: "info.circle")
19
- .foregroundColor(Colors.black09)
20
- .frame(width: 16, height: 16)
21
- .padding(.leading, -4)
22
21
  .padding(.trailing, 8)
22
+ floatingIcon
23
23
  }
24
24
  .background(Colors.black01)
25
25
  .offset(x: 16, y:-8)
@@ -27,72 +27,181 @@ fileprivate struct FloatingComponent: View {
27
27
  }
28
28
  }
29
29
 
30
+ struct DotTextField: View{
31
+ @Binding var value: String
32
+ @State var isHide: Bool = true
33
+
34
+
35
+ func onToggle(){
36
+ isHide.toggle()
37
+ }
38
+
39
+ public var body: some View {
40
+ return HStack {
41
+ if (isHide){
42
+ SecureField("", text: $value)
43
+ }
44
+ else {
45
+ TextField("", text: $value)
46
+ }
47
+
48
+ SwiftButton(action: onToggle){
49
+ Image(systemName: isHide ? "eye.slash" : "eye")
50
+ .foregroundColor(Colors.text)
51
+ .frame(width: 16, height: 16)
52
+ .padding(.leading, -4)
53
+ }
54
+
55
+
56
+ }
57
+
58
+ }
59
+ }
60
+
30
61
  public struct Input: View {
31
- @State var value: String = ""
62
+ @Binding var value: String
32
63
  @State var focused: Bool = false
33
64
 
34
- var iconPadding: CGFloat
35
- var multilines: Bool
36
65
  var placeholder: String
37
66
  var floatingValue: String
38
67
  var errorMessage: String
68
+ var errorSpacing: Bool
69
+ var isSecure: Bool
70
+ var keyboardType: UIKeyboardType
71
+ var floatingIcon: AnyView?
72
+ var rightIcon: AnyView?
73
+ var onChange: ((String) -> Void)?
74
+ var onBlur: (() -> Void)?
75
+ var floatingIconURL: String?
76
+ var floatingIconColor: Color?
77
+ var size: InputSize
78
+ var fontWeight: InputFontWeight
79
+ var disabled: Bool
80
+ var leadingIcon: String?
81
+ var leadingIconColor: Color?
82
+ var loading: Bool
83
+ var required: Bool
84
+ var hintText: String?
39
85
 
40
- func onEditingChanged(_ focused: Bool){
41
- self.focused = focused
86
+ func onCancel(){
87
+ self.value.removeAll()
42
88
  }
43
89
 
44
- public init(placeholder: String = "", floatingValue: String = "", multilines: Bool = false, errorMessage: String = ""){
90
+ public init(_ value: Binding<String>, placeholder: String = "", floatingValue: String = "", multilines: Bool = false, errorMessage: String = "", isSecure: Bool = false, keyboardType: UIKeyboardType = .default, floatingIcon: AnyView? = nil, rightIcon: AnyView? = nil, onChange: ((String)->Void)? = nil, onBlur: (()->Void)? = nil, floatingIconURL: String? = nil, floatingIconColor: Color? = Colors.pink03, size: InputSize = .small, fontWeight: InputFontWeight = .regular, disabled: Bool = false, leadingIcon: String? = nil, leadingIconColor: Color? = Colors.pink03, loading: Bool = false, required: Bool = false, hintText: String? = nil, errorSpacing: Bool = false){
45
91
  self.placeholder = placeholder
46
92
  self.floatingValue = floatingValue
47
- self.multilines = multilines
48
- self.iconPadding = multilines == true ? 16 : 0
49
93
  self.errorMessage = errorMessage
94
+ self.isSecure = isSecure
95
+ self._value = value
96
+ self.keyboardType = keyboardType
97
+ self.rightIcon = rightIcon
98
+ self.floatingIcon = floatingIcon
99
+ self.onChange = onChange
100
+ self.floatingIconURL = floatingIconURL
101
+ self.floatingIconColor = floatingIconColor
102
+ self.size = size
103
+ self.fontWeight = fontWeight
104
+ self.disabled = disabled
105
+ self.leadingIcon = leadingIcon
106
+ self.leadingIconColor = leadingIconColor
107
+ self.loading = loading
108
+ self.required = required
109
+ self.hintText = hintText
110
+ self.errorSpacing = errorSpacing
111
+ }
112
+
113
+ func onChangeText(value: String){
114
+ onChange?(value)
50
115
  }
51
116
 
52
117
  public var body: some View {
53
- return ZStack (alignment: .topLeading){
54
-
55
- HStack(alignment: multilines == true ? .top : .center){
56
- if (multilines){
57
- if #available(iOS 14.0, *) {
58
- TextEditor(text: $value)
59
- .frame(maxWidth: .infinity, minHeight: 48)
60
- .padding(.horizontal, 8)
61
- .padding(.top,4 )
62
- .accentColor(Colors.pink03)
63
- .fixedSize(horizontal: false, vertical: true)
118
+ VStack(alignment: .leading, spacing: 4) {
119
+ ZStack(alignment: .topLeading) {
120
+ HStack(alignment: .center) {
121
+ if let leadingIcon = leadingIcon {
122
+ Icon(source: leadingIcon, size: 16, color: leadingIconColor)
123
+ }
124
+
125
+ if !isSecure {
126
+ TextField("", text: $value, onEditingChanged: { isChange in
127
+ self.focused = isChange
128
+ })
129
+ .disabled(disabled)
130
+ .font(fontWeight == .bold ? .headline : .body)
131
+ } else {
132
+ DotTextField(value: $value)
133
+ .disabled(disabled)
134
+ }
135
+
136
+ if loading {
137
+ ActivityIndicator(isAnimating: .constant(true), style: .medium)
138
+ .frame(width: 20, height: 20)
139
+ } else if !value.isEmpty {
140
+ SwiftButton(action: onCancel){
141
+ Image(systemName: "x.circle.fill")
142
+ .foregroundColor(Colors.text)
143
+ .frame(width: 16, height: 16)
144
+ .padding(.leading, -4)
145
+ .padding(.trailing, 8)
146
+ }
147
+ }
148
+
149
+ rightIcon
64
150
  }
65
- }
66
- else {
67
- TextField("",text: $value, onEditingChanged:{ isChange in
68
- onEditingChanged(isChange)
69
- })
70
151
  .padding(.horizontal, 12)
71
- .accentColor(Colors.pink03)
152
+ .frame(height: scaleSize(size == .small ? 48 : 56, 1.1))
153
+ .background(
154
+ RoundedRectangle(cornerRadius: Radius.S)
155
+ .fill(Colors.black01)
156
+ )
157
+ .overlay(RoundedRectangle(cornerRadius: 8).stroke(focused ? Colors.pink03 : Colors.border, lineWidth: 1))
72
158
 
159
+ if value.isEmpty {
160
+ MomoText(placeholder + (required ? " *" : ""), typography: size == .small ? .headerSSemibold : .headerMBold, color: Colors.black09)
161
+ .padding(.horizontal, leadingIcon == nil ? 12 : 32)
162
+ .padding(.top, 12)
163
+ .allowsHitTesting(false)
164
+ }
73
165
 
166
+ if !floatingValue.isEmpty {
167
+ FloatingComponent(floatingValue, floatingIcon: floatingIconURL.map { url in
168
+ AnyView(
169
+ Icon(source: url, size: 16, color: floatingIconColor)
170
+ )
171
+ })
172
+
173
+ }
74
174
  }
75
175
 
76
- Image(systemName: "info.circle")
77
- .foregroundColor(Colors.black09)
78
- .frame(width: 16, height: 16)
79
- .padding(.leading, -4)
80
- .padding(.trailing, 8)
81
- .padding(.top, iconPadding)
82
- }
83
- .frame(maxWidth: .infinity, minHeight: 48)
84
- .overlay(RoundedRectangle(cornerRadius: 8).stroke(focused == true ? Colors.pink03 : Colors.border, lineWidth: 1))
85
- .padding(.horizontal, 1)
86
- if (value.isEmpty){
87
- Text(placeholder)
88
- .font(.system(size: 16))
89
- .foregroundColor(Colors.black09)
90
- .padding(.leading, 12)
91
- .padding(.top, 14)
92
- .allowsHitTesting(false)
176
+ ErrorView(
177
+ errorMessage: errorMessage,
178
+ errorSpacing: errorSpacing,
179
+ hintText: hintText ?? ""
180
+ )
93
181
  }
94
- FloatingComponent(floatingValue)
95
- }.padding(.bottom, 8)
182
+ }
183
+ }
184
+
185
+
186
+ struct ActivityIndicator: UIViewRepresentable {
187
+ @Binding var isAnimating: Bool
188
+ let style: UIActivityIndicatorView.Style
189
+
190
+ func makeUIView(context: UIViewRepresentableContext<ActivityIndicator>) -> UIActivityIndicatorView {
191
+ return UIActivityIndicatorView(style: style)
96
192
  }
97
-
193
+
194
+ func updateUIView(_ uiView: UIActivityIndicatorView, context: UIViewRepresentableContext<ActivityIndicator>) {
195
+ isAnimating ? uiView.startAnimating() : uiView.stopAnimating()
196
+ }
197
+ }
198
+
199
+ public enum InputSize {
200
+ case small
201
+ case large
202
+ }
203
+
204
+ public enum InputFontWeight {
205
+ case regular
206
+ case bold
98
207
  }