@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,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: "
|
|
20
|
-
public static let black19 = Color(hex: "
|
|
21
|
-
public static let black18 = Color(hex: "
|
|
22
|
-
public static let black17 = Color(hex: "
|
|
23
|
-
public static let black16 = Color(hex: "
|
|
24
|
-
public static let black15 = Color(hex: "
|
|
25
|
-
public static let black14 = Color(hex: "
|
|
26
|
-
public static let black13 = Color(hex: "
|
|
27
|
-
public static let black12 = Color(hex: "
|
|
28
|
-
public static let black11 = Color(hex: "
|
|
29
|
-
public static let black10 = Color(hex: "
|
|
30
|
-
public static let black09 = Color(hex: "
|
|
31
|
-
public static let black08 = Color(hex: "
|
|
32
|
-
public static let black07 = Color(hex: "
|
|
33
|
-
public static let black06 = Color(hex: "
|
|
34
|
-
public static let black05 = Color(hex: "
|
|
35
|
-
public static let black04 = Color(hex: "
|
|
36
|
-
public static let black03 = Color(hex: "
|
|
37
|
-
public static let black02 = Color(hex: "
|
|
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
|
+
}
|
package/ios/Input/Input.swift
CHANGED
|
@@ -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
|
-
@
|
|
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
|
|
41
|
-
self.
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
.
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
-
|
|
95
|
-
|
|
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
|
}
|