@momo-kits/native-kits 0.157.4 → 0.157.5
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/ios/Input/Input.swift +112 -50
- package/package.json +1 -1
package/ios/Input/Input.swift
CHANGED
|
@@ -32,7 +32,6 @@ public struct Input: View {
|
|
|
32
32
|
|
|
33
33
|
@State private var isFocused: Bool = false
|
|
34
34
|
@State private var isPasswordHidden: Bool = true
|
|
35
|
-
@State private var lastTextValue: String = ""
|
|
36
35
|
|
|
37
36
|
public init(
|
|
38
37
|
text: Binding<String>,
|
|
@@ -93,14 +92,6 @@ public struct Input: View {
|
|
|
93
92
|
let textBinding = Binding<String>(
|
|
94
93
|
get: { self.text },
|
|
95
94
|
set: { newValue in
|
|
96
|
-
// For SecureField, infer focus when text changes
|
|
97
|
-
if self.secureTextEntry && !self.isFocused && newValue != self.lastTextValue {
|
|
98
|
-
DispatchQueue.main.async {
|
|
99
|
-
self.isFocused = true
|
|
100
|
-
self.onFocus?()
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
self.lastTextValue = newValue
|
|
104
95
|
self.text = newValue
|
|
105
96
|
self.onChangeText?(newValue)
|
|
106
97
|
}
|
|
@@ -144,17 +135,18 @@ public struct Input: View {
|
|
|
144
135
|
}
|
|
145
136
|
|
|
146
137
|
if secureTextEntry && isPasswordHidden {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
138
|
+
SecureInputField(
|
|
139
|
+
text: $text,
|
|
140
|
+
keyboardType: keyboardType,
|
|
141
|
+
fontSize: scaleSize(14),
|
|
142
|
+
fontWeight: fontWeight == .bold ? .bold : .regular,
|
|
143
|
+
textColor: UIColor(getTextColor()),
|
|
144
|
+
isDisabled: disabled || readOnly,
|
|
145
|
+
onFocusChange: { focused in
|
|
146
|
+
handleFocusChange(focused)
|
|
147
|
+
},
|
|
148
|
+
onChangeText: onChangeText
|
|
149
|
+
)
|
|
158
150
|
} else {
|
|
159
151
|
TextField("", text: textBinding, onEditingChanged: { focused in
|
|
160
152
|
handleFocusChange(focused)
|
|
@@ -223,26 +215,10 @@ public struct Input: View {
|
|
|
223
215
|
hintText: hintText
|
|
224
216
|
)
|
|
225
217
|
}
|
|
226
|
-
.onAppear {
|
|
227
|
-
lastTextValue = text
|
|
228
|
-
}
|
|
229
218
|
.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)) { _ in
|
|
230
|
-
|
|
231
|
-
if isFocused {
|
|
219
|
+
if isFocused && !secureTextEntry {
|
|
232
220
|
DispatchQueue.main.async {
|
|
233
|
-
|
|
234
|
-
handleSecureFieldBlur()
|
|
235
|
-
} else {
|
|
236
|
-
handleFocusChange(false)
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
.onReceive(NotificationCenter.default.publisher(for: UITextField.textDidEndEditingNotification)) { _ in
|
|
242
|
-
// Reset focus when any text field ends editing
|
|
243
|
-
if isFocused && secureTextEntry {
|
|
244
|
-
DispatchQueue.main.async {
|
|
245
|
-
self.handleSecureFieldBlur()
|
|
221
|
+
handleFocusChange(false)
|
|
246
222
|
}
|
|
247
223
|
}
|
|
248
224
|
}
|
|
@@ -259,18 +235,6 @@ public struct Input: View {
|
|
|
259
235
|
}
|
|
260
236
|
}
|
|
261
237
|
|
|
262
|
-
private func handleSecureFieldFocus() {
|
|
263
|
-
if !isFocused {
|
|
264
|
-
isFocused = true
|
|
265
|
-
onFocus?()
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
private func handleSecureFieldBlur() {
|
|
270
|
-
isFocused = false
|
|
271
|
-
onBlur?()
|
|
272
|
-
}
|
|
273
|
-
|
|
274
238
|
private func togglePasswordVisibility() {
|
|
275
239
|
isPasswordHidden.toggle()
|
|
276
240
|
onRightIconPressed?()
|
|
@@ -307,6 +271,104 @@ public struct Input: View {
|
|
|
307
271
|
}
|
|
308
272
|
|
|
309
273
|
|
|
274
|
+
// MARK: - Secure Input Field (UIViewRepresentable)
|
|
275
|
+
private struct SecureInputField: UIViewRepresentable {
|
|
276
|
+
@Binding var text: String
|
|
277
|
+
var keyboardType: UIKeyboardType
|
|
278
|
+
var fontSize: CGFloat
|
|
279
|
+
var fontWeight: UIFont.Weight
|
|
280
|
+
var textColor: UIColor
|
|
281
|
+
var isDisabled: Bool
|
|
282
|
+
var onFocusChange: (Bool) -> Void
|
|
283
|
+
var onChangeText: ((String) -> Void)?
|
|
284
|
+
|
|
285
|
+
func makeCoordinator() -> Coordinator {
|
|
286
|
+
Coordinator(self)
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
func makeUIView(context: Context) -> UITextField {
|
|
290
|
+
let textField = UITextField()
|
|
291
|
+
textField.isSecureTextEntry = true
|
|
292
|
+
textField.delegate = context.coordinator
|
|
293
|
+
textField.keyboardType = keyboardType
|
|
294
|
+
textField.font = UIFont.systemFont(ofSize: fontSize, weight: fontWeight)
|
|
295
|
+
textField.textColor = textColor
|
|
296
|
+
textField.isEnabled = !isDisabled
|
|
297
|
+
textField.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
|
298
|
+
textField.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
|
299
|
+
textField.text = text
|
|
300
|
+
textField.tintColor = UIColor(Colors.primary)
|
|
301
|
+
textField.addTarget(
|
|
302
|
+
context.coordinator,
|
|
303
|
+
action: #selector(Coordinator.textFieldDidChange(_:)),
|
|
304
|
+
for: .editingChanged
|
|
305
|
+
)
|
|
306
|
+
return textField
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
func updateUIView(_ textField: UITextField, context: Context) {
|
|
310
|
+
if textField.text != text {
|
|
311
|
+
textField.text = text
|
|
312
|
+
}
|
|
313
|
+
textField.isEnabled = !isDisabled
|
|
314
|
+
if textField.keyboardType != keyboardType {
|
|
315
|
+
textField.keyboardType = keyboardType
|
|
316
|
+
textField.reloadInputViews()
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
class Coordinator: NSObject, UITextFieldDelegate {
|
|
321
|
+
var parent: SecureInputField
|
|
322
|
+
private var isResettingText = false
|
|
323
|
+
|
|
324
|
+
init(_ parent: SecureInputField) {
|
|
325
|
+
self.parent = parent
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
func textFieldDidBeginEditing(_ textField: UITextField) {
|
|
329
|
+
let existingText = textField.text ?? ""
|
|
330
|
+
if !existingText.isEmpty {
|
|
331
|
+
// When a secure text field regains focus, iOS marks the
|
|
332
|
+
// existing text as "committed". The next keystroke would
|
|
333
|
+
// replace ALL committed text with the new character.
|
|
334
|
+
// Prevent this by clearing and re-inserting via insertText(),
|
|
335
|
+
// which puts the text into an "active editing" state.
|
|
336
|
+
isResettingText = true
|
|
337
|
+
textField.text = ""
|
|
338
|
+
textField.insertText(existingText)
|
|
339
|
+
isResettingText = false
|
|
340
|
+
}
|
|
341
|
+
parent.onFocusChange(true)
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
func textFieldDidEndEditing(_ textField: UITextField) {
|
|
345
|
+
parent.text = textField.text ?? ""
|
|
346
|
+
parent.onFocusChange(false)
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
func textField(
|
|
350
|
+
_ textField: UITextField,
|
|
351
|
+
shouldChangeCharactersIn range: NSRange,
|
|
352
|
+
replacementString string: String
|
|
353
|
+
) -> Bool {
|
|
354
|
+
if isResettingText { return true }
|
|
355
|
+
return true
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
@objc func textFieldDidChange(_ textField: UITextField) {
|
|
359
|
+
if isResettingText { return }
|
|
360
|
+
let newText = textField.text ?? ""
|
|
361
|
+
parent.text = newText
|
|
362
|
+
parent.onChangeText?(newText)
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
|
366
|
+
textField.resignFirstResponder()
|
|
367
|
+
return true
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
310
372
|
// MARK: - Helper Extension
|
|
311
373
|
private extension View {
|
|
312
374
|
func applyPrimaryCursorColor() -> some View {
|