@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,158 @@
|
|
|
1
|
+
//
|
|
2
|
+
// InputPhoneNumber.swift
|
|
3
|
+
// Pods
|
|
4
|
+
//
|
|
5
|
+
// Created by sophia on 20/10/25.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import SwiftUI
|
|
9
|
+
|
|
10
|
+
public struct InputPhoneNumber: View {
|
|
11
|
+
@Binding public var text: String
|
|
12
|
+
|
|
13
|
+
public var placeholder: String
|
|
14
|
+
public var size: InputSize
|
|
15
|
+
public var hintText: String
|
|
16
|
+
public var error: String
|
|
17
|
+
public var loading: Bool
|
|
18
|
+
public var rightIcon: String
|
|
19
|
+
public var rightIconColor: Color
|
|
20
|
+
public var onFocus: (() -> Void)?
|
|
21
|
+
public var onBlur: (() -> Void)?
|
|
22
|
+
public var onRightIconPressed: (() -> Void)?
|
|
23
|
+
|
|
24
|
+
@State private var isFocused: Bool = false
|
|
25
|
+
|
|
26
|
+
public init(
|
|
27
|
+
text: Binding<String>,
|
|
28
|
+
placeholder: String = "0123456789",
|
|
29
|
+
size: InputSize = .small,
|
|
30
|
+
hintText: String = "",
|
|
31
|
+
error: String = "",
|
|
32
|
+
loading: Bool = false,
|
|
33
|
+
required: Bool = false,
|
|
34
|
+
rightIcon: String = "",
|
|
35
|
+
rightIconColor: Color = Colors.black12,
|
|
36
|
+
onFocus: (() -> Void)? = nil,
|
|
37
|
+
onBlur: (() -> Void)? = nil,
|
|
38
|
+
onRightIconPressed: (() -> Void)? = nil
|
|
39
|
+
) {
|
|
40
|
+
self._text = text
|
|
41
|
+
self.placeholder = placeholder
|
|
42
|
+
self.size = size
|
|
43
|
+
self.hintText = hintText
|
|
44
|
+
self.error = error
|
|
45
|
+
self.loading = loading
|
|
46
|
+
self.rightIcon = rightIcon
|
|
47
|
+
self.rightIconColor = rightIconColor
|
|
48
|
+
self.onFocus = onFocus
|
|
49
|
+
self.onBlur = onBlur
|
|
50
|
+
self.onRightIconPressed = onRightIconPressed
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// MARK: - Body
|
|
54
|
+
public var body: some View {
|
|
55
|
+
VStack(alignment: .leading, spacing: 4) {
|
|
56
|
+
HStack(spacing: 0) {
|
|
57
|
+
// 🇻🇳 Flag
|
|
58
|
+
ImageView("https://static.momocdn.net/app/img/icon/ic-qrcode-package/ic_vn_flag.png")
|
|
59
|
+
.frame(width: 24, height: 24)
|
|
60
|
+
.padding(.trailing, Spacing.XS)
|
|
61
|
+
|
|
62
|
+
MomoText("+84", typography: size == .small ? .headerSSemibold : .headerMBold)
|
|
63
|
+
.foregroundColor(Colors.black17)
|
|
64
|
+
|
|
65
|
+
Rectangle()
|
|
66
|
+
.fill(Colors.black04)
|
|
67
|
+
.frame(width: 1, height: size == .small ? 24 : 32)
|
|
68
|
+
.padding(.horizontal, Spacing.M)
|
|
69
|
+
|
|
70
|
+
// Text input
|
|
71
|
+
ZStack(alignment: .leading) {
|
|
72
|
+
if text.isEmpty {
|
|
73
|
+
MomoText(placeholder, typography: size == .small ? .headerSSemibold : .headerMBold, color: Colors.black12)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
TextField("", text: $text, onEditingChanged: { focused in
|
|
77
|
+
handleFocusChange(focused)
|
|
78
|
+
})
|
|
79
|
+
.keyboardType(.numberPad)
|
|
80
|
+
.font(size == .small ? .header_s_semibold : .header_m_bold)
|
|
81
|
+
.foregroundColor(Colors.black17)
|
|
82
|
+
.applyPrimaryCursorColor()
|
|
83
|
+
.lineLimit(1)
|
|
84
|
+
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Clear button
|
|
88
|
+
if isFocused && !text.isEmpty {
|
|
89
|
+
SwiftUI.Button(action: { text = "" }) {
|
|
90
|
+
Icon(source: "24_navigation_close_circle_full", size: 16, color: Colors.black12)
|
|
91
|
+
.padding(.leading, Spacing.S)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Loading indicator
|
|
96
|
+
if loading {
|
|
97
|
+
ActivityIndicator(isAnimating: .constant(true), style: .medium)
|
|
98
|
+
.frame(width: 16, height: 16)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ✅ Right icon
|
|
102
|
+
if !rightIcon.isEmpty {
|
|
103
|
+
SwiftUI.Button(action: { onRightIconPressed?() }) {
|
|
104
|
+
Icon(source: rightIcon, size: 24, color: rightIconColor)
|
|
105
|
+
.padding(.leading, Spacing.S)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
.padding(.horizontal, Spacing.M)
|
|
110
|
+
.frame(height: scaleSize(size == .small ? 48 : 56, 1.1))
|
|
111
|
+
.background(
|
|
112
|
+
RoundedRectangle(cornerRadius: Radius.S)
|
|
113
|
+
.fill(Colors.black01)
|
|
114
|
+
)
|
|
115
|
+
.overlay(
|
|
116
|
+
RoundedRectangle(cornerRadius: Radius.S)
|
|
117
|
+
.stroke(borderColor(), lineWidth: isFocused ? 1.5 : 1)
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
// Error or hint
|
|
121
|
+
ErrorView(
|
|
122
|
+
errorMessage: error,
|
|
123
|
+
errorSpacing: false,
|
|
124
|
+
hintText: hintText
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// MARK: - Helpers
|
|
130
|
+
|
|
131
|
+
private func handleFocusChange(_ focused: Bool) {
|
|
132
|
+
isFocused = focused
|
|
133
|
+
if focused {
|
|
134
|
+
onFocus?()
|
|
135
|
+
} else {
|
|
136
|
+
onBlur?()
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private func borderColor() -> Color {
|
|
141
|
+
if !error.isEmpty { return Colors.red03 }
|
|
142
|
+
if isFocused { return Colors.primary }
|
|
143
|
+
return Colors.black04
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
private extension View {
|
|
148
|
+
func applyPrimaryCursorColor() -> some View {
|
|
149
|
+
if #available(iOS 15.0, *) {
|
|
150
|
+
// Modern SwiftUI: use .tint() for cursor
|
|
151
|
+
return self.tint(Colors.primary)
|
|
152
|
+
} else {
|
|
153
|
+
// iOS 13–14: return unchanged (no tint support)
|
|
154
|
+
return self
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
//
|
|
2
|
+
// InputSearch.swift
|
|
3
|
+
// Pods
|
|
4
|
+
//
|
|
5
|
+
// Created by dung.pham2 on 3/12/24.
|
|
6
|
+
//
|
|
7
|
+
import SwiftUI
|
|
8
|
+
|
|
9
|
+
// MARK: - RenderRightIconSearch
|
|
10
|
+
|
|
11
|
+
struct RenderRightIconSearch: View {
|
|
12
|
+
let loading: Bool
|
|
13
|
+
let icon: String
|
|
14
|
+
let color: Color
|
|
15
|
+
let onClick: () -> Void
|
|
16
|
+
|
|
17
|
+
var body: some View {
|
|
18
|
+
HStack(spacing: 0) {
|
|
19
|
+
if loading {
|
|
20
|
+
ActivityIndicator(isAnimating: .constant(true), style: .medium)
|
|
21
|
+
.frame(width: 16, height: 16)
|
|
22
|
+
.padding(.horizontal, Spacing.S)
|
|
23
|
+
}
|
|
24
|
+
if !icon.isEmpty {
|
|
25
|
+
Divider()
|
|
26
|
+
.frame(width: 1)
|
|
27
|
+
.background(Colors.primary)
|
|
28
|
+
.padding(.leading, Spacing.S)
|
|
29
|
+
|
|
30
|
+
Image(systemName: icon)
|
|
31
|
+
.foregroundColor(color)
|
|
32
|
+
.frame(width: 24, height: 24)
|
|
33
|
+
.padding(.leading, Spacing.S)
|
|
34
|
+
.onTapGesture(perform: onClick)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public struct InputSearchProps {
|
|
41
|
+
@Binding var text: String
|
|
42
|
+
var buttonText: String = ""
|
|
43
|
+
var showButtonText: Bool = false
|
|
44
|
+
var showBorder: Bool = true
|
|
45
|
+
var placeholder: String = ""
|
|
46
|
+
var onChangeText: (String) -> Void = { _ in }
|
|
47
|
+
var onPressButtonText: () -> Void = {}
|
|
48
|
+
var error: String = ""
|
|
49
|
+
var disabled: Bool = false
|
|
50
|
+
var icon: String = ""
|
|
51
|
+
var iconColor: Color = Colors.text
|
|
52
|
+
var onRightIconPressed: () -> Void = {}
|
|
53
|
+
var onFocus: () -> Void = {}
|
|
54
|
+
var onBlur: () -> Void = {}
|
|
55
|
+
var loading: Bool = false
|
|
56
|
+
var fontWeight: Font.Weight = .regular
|
|
57
|
+
var keyboardType: UIKeyboardType = .default
|
|
58
|
+
|
|
59
|
+
public init(text: Binding<String>,
|
|
60
|
+
buttonText: String = "",
|
|
61
|
+
showButtonText: Bool = false,
|
|
62
|
+
showBorder: Bool = true,
|
|
63
|
+
placeholder: String = "",
|
|
64
|
+
onChangeText: @escaping (String) -> Void = { _ in },
|
|
65
|
+
onPressButtonText: @escaping () -> Void = {},
|
|
66
|
+
error: String = "",
|
|
67
|
+
disabled: Bool = false,
|
|
68
|
+
icon: String = "",
|
|
69
|
+
iconColor: Color = Colors.text,
|
|
70
|
+
onRightIconPressed: @escaping () -> Void = {},
|
|
71
|
+
onFocus: @escaping () -> Void = {},
|
|
72
|
+
onBlur: @escaping () -> Void = {},
|
|
73
|
+
loading: Bool = false,
|
|
74
|
+
fontWeight: Font.Weight = .regular,
|
|
75
|
+
keyboardType: UIKeyboardType = .default) {
|
|
76
|
+
self._text = text
|
|
77
|
+
self.buttonText = buttonText
|
|
78
|
+
self.showButtonText = showButtonText
|
|
79
|
+
self.showBorder = showBorder
|
|
80
|
+
self.placeholder = placeholder
|
|
81
|
+
self.onChangeText = onChangeText
|
|
82
|
+
self.onPressButtonText = onPressButtonText
|
|
83
|
+
self.error = error
|
|
84
|
+
self.disabled = disabled
|
|
85
|
+
self.icon = icon
|
|
86
|
+
self.iconColor = iconColor
|
|
87
|
+
self.onRightIconPressed = onRightIconPressed
|
|
88
|
+
self.onFocus = onFocus
|
|
89
|
+
self.onBlur = onBlur
|
|
90
|
+
self.loading = loading
|
|
91
|
+
self.fontWeight = fontWeight
|
|
92
|
+
self.keyboardType = keyboardType
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// MARK: - InputSearch
|
|
97
|
+
|
|
98
|
+
public struct InputSearch: View {
|
|
99
|
+
@Binding var text: String
|
|
100
|
+
var buttonText: String = ""
|
|
101
|
+
var showButtonText: Bool = false
|
|
102
|
+
var showBorder: Bool = true
|
|
103
|
+
var placeholder: String = ""
|
|
104
|
+
var onChangeText: (String) -> Void = { _ in }
|
|
105
|
+
var onPressButtonText: () -> Void = {}
|
|
106
|
+
var error: String = ""
|
|
107
|
+
var disabled: Bool = false
|
|
108
|
+
var icon: String = ""
|
|
109
|
+
var iconColor: Color = Colors.text
|
|
110
|
+
var onRightIconPressed: () -> Void = {}
|
|
111
|
+
var onFocus: () -> Void = {}
|
|
112
|
+
var onBlur: () -> Void = {}
|
|
113
|
+
var loading: Bool = false
|
|
114
|
+
var fontWeight: Font.Weight = .regular
|
|
115
|
+
var keyboardType: UIKeyboardType = .default
|
|
116
|
+
|
|
117
|
+
@State private var isFocused = false
|
|
118
|
+
@State private var isBlurred = false
|
|
119
|
+
|
|
120
|
+
public init(text: Binding<String>,
|
|
121
|
+
buttonText: String = "",
|
|
122
|
+
showButtonText: Bool = false,
|
|
123
|
+
showBorder: Bool = true,
|
|
124
|
+
placeholder: String = "",
|
|
125
|
+
onChangeText: @escaping (String) -> Void = { _ in },
|
|
126
|
+
onPressButtonText: @escaping () -> Void = {},
|
|
127
|
+
error: String = "",
|
|
128
|
+
disabled: Bool = false,
|
|
129
|
+
icon: String = "",
|
|
130
|
+
iconColor: Color = Colors.text,
|
|
131
|
+
onRightIconPressed: @escaping () -> Void = {},
|
|
132
|
+
onFocus: @escaping () -> Void = {},
|
|
133
|
+
onBlur: @escaping () -> Void = {},
|
|
134
|
+
loading: Bool = false,
|
|
135
|
+
fontWeight: Font.Weight = .regular,
|
|
136
|
+
keyboardType: UIKeyboardType = .default) {
|
|
137
|
+
self._text = text
|
|
138
|
+
self.buttonText = buttonText
|
|
139
|
+
self.showButtonText = showButtonText
|
|
140
|
+
self.showBorder = showBorder
|
|
141
|
+
self.placeholder = placeholder
|
|
142
|
+
self.onChangeText = onChangeText
|
|
143
|
+
self.onPressButtonText = onPressButtonText
|
|
144
|
+
self.error = error
|
|
145
|
+
self.disabled = disabled
|
|
146
|
+
self.icon = icon
|
|
147
|
+
self.iconColor = iconColor
|
|
148
|
+
self.onRightIconPressed = onRightIconPressed
|
|
149
|
+
self.onFocus = onFocus
|
|
150
|
+
self.onBlur = onBlur
|
|
151
|
+
self.loading = loading
|
|
152
|
+
self.fontWeight = fontWeight
|
|
153
|
+
self.keyboardType = keyboardType
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
public var body: some View {
|
|
158
|
+
VStack(alignment: .leading, spacing: 0) {
|
|
159
|
+
HStack(spacing: 0) {
|
|
160
|
+
HStack {
|
|
161
|
+
Image(systemName: "magnifyingglass")
|
|
162
|
+
.foregroundColor(Colors.black12)
|
|
163
|
+
.frame(width: 24, height: 24)
|
|
164
|
+
.padding(.trailing, Spacing.XS)
|
|
165
|
+
|
|
166
|
+
ZStack(alignment: .leading) {
|
|
167
|
+
if text.isEmpty {
|
|
168
|
+
Text(placeholder)
|
|
169
|
+
.foregroundColor(disabled ? Colors.black08 : Colors.black12)
|
|
170
|
+
.font(.system(size: 16, weight: fontWeight))
|
|
171
|
+
}
|
|
172
|
+
TextField("", text: $text, onEditingChanged: { editing in
|
|
173
|
+
isFocused = editing
|
|
174
|
+
if editing {
|
|
175
|
+
onFocus()
|
|
176
|
+
} else if isBlurred {
|
|
177
|
+
onBlur()
|
|
178
|
+
}
|
|
179
|
+
if editing && !isBlurred {
|
|
180
|
+
isBlurred = true
|
|
181
|
+
}
|
|
182
|
+
}, onCommit: {})
|
|
183
|
+
.disabled(disabled)
|
|
184
|
+
.foregroundColor(disabled ? Colors.black08 : Colors.black17)
|
|
185
|
+
.font(.system(size: 15, weight: fontWeight))
|
|
186
|
+
.keyboardType(keyboardType)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if isFocused && !text.isEmpty {
|
|
190
|
+
SwiftButton(action: { text = "" }) {
|
|
191
|
+
Image(systemName: "xmark.circle.fill")
|
|
192
|
+
.foregroundColor(Colors.black12)
|
|
193
|
+
.frame(width: 16, height: 16)
|
|
194
|
+
}
|
|
195
|
+
.padding(.leading, Spacing.S)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
RenderRightIconSearch(loading: loading, icon: icon, color: disabled ? Colors.black08 : iconColor, onClick: onRightIconPressed)
|
|
199
|
+
}
|
|
200
|
+
.padding(.horizontal, Spacing.M)
|
|
201
|
+
.padding(.vertical, Spacing.S)
|
|
202
|
+
.background(Colors.black01)
|
|
203
|
+
.cornerRadius(Radius.XL)
|
|
204
|
+
.overlay(
|
|
205
|
+
RoundedRectangle(cornerRadius: Radius.XL)
|
|
206
|
+
.stroke(getBorderColor(isFocused: isFocused, error: error, disabled: disabled), lineWidth: showBorder ? 1 : 0)
|
|
207
|
+
)
|
|
208
|
+
.frame(maxWidth: showButtonText ? .infinity : nil, alignment: .leading)
|
|
209
|
+
|
|
210
|
+
if showButtonText {
|
|
211
|
+
SwiftButton(action: onPressButtonText) {
|
|
212
|
+
Text(buttonText)
|
|
213
|
+
.foregroundColor(Colors.black17)
|
|
214
|
+
.font(.system(size: 14, weight: .medium))
|
|
215
|
+
}
|
|
216
|
+
.padding(.leading, Spacing.L)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// MARK: - Helper Functions
|
|
224
|
+
|
|
225
|
+
func getBorderColor(isFocused: Bool, error: String, disabled: Bool) -> Color {
|
|
226
|
+
if disabled {
|
|
227
|
+
return Colors.black08
|
|
228
|
+
} else if !error.isEmpty {
|
|
229
|
+
return Colors.red03
|
|
230
|
+
} else if isFocused {
|
|
231
|
+
return Colors.primary
|
|
232
|
+
} else {
|
|
233
|
+
return Colors.black04
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
//
|
|
2
|
+
// InputTextArea.swift
|
|
3
|
+
// Pods
|
|
4
|
+
//
|
|
5
|
+
// Created by dung.pham2 on 2/12/24.
|
|
6
|
+
//
|
|
7
|
+
import SwiftUI
|
|
8
|
+
|
|
9
|
+
// Make these constants public
|
|
10
|
+
public let MAX_LENGTH = 300
|
|
11
|
+
public let DEFAULT_HEIGHT: CGFloat = 104
|
|
12
|
+
|
|
13
|
+
struct UITextViewWrapper: UIViewRepresentable {
|
|
14
|
+
@Binding var text: String
|
|
15
|
+
var onDone: (() -> Void)?
|
|
16
|
+
var onFocus: (() -> Void)?
|
|
17
|
+
var onBlur: (() -> Void)?
|
|
18
|
+
|
|
19
|
+
func makeUIView(context: Context) -> UITextView {
|
|
20
|
+
let textView = UITextView()
|
|
21
|
+
textView.delegate = context.coordinator
|
|
22
|
+
return textView
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
func updateUIView(_ uiView: UITextView, context: Context) {
|
|
26
|
+
uiView.text = text
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
func makeCoordinator() -> Coordinator {
|
|
30
|
+
Coordinator(self)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
class Coordinator: NSObject, UITextViewDelegate {
|
|
34
|
+
var parent: UITextViewWrapper
|
|
35
|
+
|
|
36
|
+
init(_ parent: UITextViewWrapper) {
|
|
37
|
+
self.parent = parent
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
func textViewDidChange(_ textView: UITextView) {
|
|
41
|
+
parent.text = textView.text
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
func textViewDidBeginEditing(_ textView: UITextView) {
|
|
45
|
+
parent.onFocus?()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
func textViewDidEndEditing(_ textView: UITextView) {
|
|
49
|
+
parent.onBlur?()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
|
|
53
|
+
if text == "\n" {
|
|
54
|
+
parent.onDone?()
|
|
55
|
+
return false
|
|
56
|
+
}
|
|
57
|
+
return true
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Make the struct public
|
|
63
|
+
public struct InputTextArea: View {
|
|
64
|
+
@Binding var text: String
|
|
65
|
+
var maxLength: Int = MAX_LENGTH
|
|
66
|
+
var height: CGFloat = DEFAULT_HEIGHT
|
|
67
|
+
var floatingValue: String = ""
|
|
68
|
+
var floatingValueColor: Color = .gray
|
|
69
|
+
var floatingIcon: String = ""
|
|
70
|
+
var floatingIconColor: Color = .black
|
|
71
|
+
var placeholder: String = ""
|
|
72
|
+
var onChangeText: (String) -> Void = { _ in }
|
|
73
|
+
var error: String = ""
|
|
74
|
+
var errorSpacing: Bool = false
|
|
75
|
+
var disabled: Bool = false
|
|
76
|
+
var icon: String = ""
|
|
77
|
+
var iconColor: Color = .black
|
|
78
|
+
var onRightIconPressed: () -> Void = {}
|
|
79
|
+
var onFocus: () -> Void = {}
|
|
80
|
+
var onBlur: () -> Void = {}
|
|
81
|
+
var loading: Bool = false
|
|
82
|
+
var required: Bool = false
|
|
83
|
+
var fontWeight: Font.Weight = .regular
|
|
84
|
+
var keyboardType: UIKeyboardType = .default
|
|
85
|
+
|
|
86
|
+
@State private var isFocused = false
|
|
87
|
+
@State private var isBlurred = false
|
|
88
|
+
|
|
89
|
+
// Make the initializer public
|
|
90
|
+
public init(
|
|
91
|
+
text: Binding<String>,
|
|
92
|
+
maxLength: Int = MAX_LENGTH,
|
|
93
|
+
height: CGFloat = DEFAULT_HEIGHT,
|
|
94
|
+
floatingValue: String = "",
|
|
95
|
+
floatingValueColor: Color = .gray,
|
|
96
|
+
floatingIcon: String = "",
|
|
97
|
+
floatingIconColor: Color = .black,
|
|
98
|
+
placeholder: String = "",
|
|
99
|
+
onChangeText: @escaping (String) -> Void = { _ in },
|
|
100
|
+
error: String = "",
|
|
101
|
+
errorSpacing: Bool = false,
|
|
102
|
+
disabled: Bool = false,
|
|
103
|
+
icon: String = "",
|
|
104
|
+
iconColor: Color = Colors.pink03,
|
|
105
|
+
onRightIconPressed: @escaping () -> Void = {},
|
|
106
|
+
onFocus: @escaping () -> Void = {},
|
|
107
|
+
onBlur: @escaping () -> Void = {},
|
|
108
|
+
loading: Bool = false,
|
|
109
|
+
required: Bool = false,
|
|
110
|
+
fontWeight: Font.Weight = .regular,
|
|
111
|
+
keyboardType: UIKeyboardType = .default
|
|
112
|
+
) {
|
|
113
|
+
self._text = text
|
|
114
|
+
self.maxLength = maxLength
|
|
115
|
+
self.height = height
|
|
116
|
+
self.floatingValue = floatingValue
|
|
117
|
+
self.floatingValueColor = floatingValueColor
|
|
118
|
+
self.floatingIcon = floatingIcon
|
|
119
|
+
self.floatingIconColor = floatingIconColor
|
|
120
|
+
self.placeholder = placeholder
|
|
121
|
+
self.onChangeText = onChangeText
|
|
122
|
+
self.error = error
|
|
123
|
+
self.errorSpacing = errorSpacing
|
|
124
|
+
self.disabled = disabled
|
|
125
|
+
self.icon = icon
|
|
126
|
+
self.iconColor = iconColor
|
|
127
|
+
self.onRightIconPressed = onRightIconPressed
|
|
128
|
+
self.onFocus = onFocus
|
|
129
|
+
self.onBlur = onBlur
|
|
130
|
+
self.loading = loading
|
|
131
|
+
self.required = required
|
|
132
|
+
self.fontWeight = fontWeight
|
|
133
|
+
self.keyboardType = keyboardType
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
public var body: some View {
|
|
137
|
+
VStack(alignment: .leading, spacing: 0) {
|
|
138
|
+
ZStack(alignment: .topLeading) {
|
|
139
|
+
if !floatingValue.isEmpty || !floatingIcon.isEmpty {
|
|
140
|
+
HStack(spacing: 4) {
|
|
141
|
+
Text(floatingValue)
|
|
142
|
+
.font(.caption)
|
|
143
|
+
.foregroundColor(disabled ? .gray : floatingValueColor)
|
|
144
|
+
|
|
145
|
+
if required {
|
|
146
|
+
Text("*")
|
|
147
|
+
.font(.caption)
|
|
148
|
+
.foregroundColor(.red)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if !floatingIcon.isEmpty {
|
|
152
|
+
Image(systemName: floatingIcon)
|
|
153
|
+
.font(.caption)
|
|
154
|
+
.foregroundColor(disabled ? .gray : floatingIconColor)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
.padding(.horizontal, 8)
|
|
158
|
+
.background(Colors.black01)
|
|
159
|
+
.offset(x: Spacing.S, y: -height / 10)
|
|
160
|
+
.zIndex(10)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
VStack {
|
|
164
|
+
ZStack(alignment: .topLeading) {
|
|
165
|
+
if text.isEmpty {
|
|
166
|
+
Text(placeholder)
|
|
167
|
+
.foregroundColor(disabled ? .gray : .gray)
|
|
168
|
+
.font(.system(size: 16, weight: fontWeight))
|
|
169
|
+
.padding(.horizontal, 16)
|
|
170
|
+
.padding(.vertical, 12)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
UITextViewWrapper(text: $text, onDone: {
|
|
174
|
+
// Handle done action if needed
|
|
175
|
+
},
|
|
176
|
+
onFocus: {
|
|
177
|
+
isFocused = true
|
|
178
|
+
onFocus()
|
|
179
|
+
}, onBlur: {
|
|
180
|
+
isFocused = false
|
|
181
|
+
isBlurred = true
|
|
182
|
+
onBlur()
|
|
183
|
+
})
|
|
184
|
+
.frame(height: height)
|
|
185
|
+
.padding(.horizontal, 12)
|
|
186
|
+
.padding(.vertical, 8)
|
|
187
|
+
.disabled(disabled) }
|
|
188
|
+
|
|
189
|
+
HStack {
|
|
190
|
+
Spacer()
|
|
191
|
+
Text("\(text.count)/\(maxLength)")
|
|
192
|
+
.font(.caption)
|
|
193
|
+
.foregroundColor(.gray)
|
|
194
|
+
}
|
|
195
|
+
.padding(.horizontal, 16)
|
|
196
|
+
.padding(.bottom, 12)
|
|
197
|
+
}
|
|
198
|
+
.background(Color.white)
|
|
199
|
+
.cornerRadius(8)
|
|
200
|
+
.overlay(
|
|
201
|
+
RoundedRectangle(cornerRadius: 8)
|
|
202
|
+
.stroke(borderColor, lineWidth: 1)
|
|
203
|
+
)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if !error.isEmpty {
|
|
207
|
+
Text(error)
|
|
208
|
+
.font(.caption)
|
|
209
|
+
.foregroundColor(.red)
|
|
210
|
+
.padding(.top, errorSpacing ? 8 : 4)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) { _ in
|
|
214
|
+
if !isBlurred {
|
|
215
|
+
isFocused = true
|
|
216
|
+
onFocus()
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)) { _ in
|
|
220
|
+
if isFocused {
|
|
221
|
+
isFocused = false
|
|
222
|
+
isBlurred = true
|
|
223
|
+
onBlur()
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private var borderColor: Color {
|
|
229
|
+
if disabled {
|
|
230
|
+
return Colors.black03
|
|
231
|
+
} else if !error.isEmpty {
|
|
232
|
+
return .red
|
|
233
|
+
} else if isFocused {
|
|
234
|
+
return Colors.pink03
|
|
235
|
+
} else {
|
|
236
|
+
return Colors.border
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
|