Skip to content

Commit ca8ab1e

Browse files
committed
feat: add setText native command
1 parent 3db476e commit ca8ab1e

16 files changed

+223
-26
lines changed

apps/example/src/components/TextInput/index.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import Button from "../Button";
1414

1515
import styles from "./styles";
1616

17-
import type { TextInput as RNTextInput } from "react-native";
17+
import type { MaskedTextInputRef } from "package/src/types";
1818

1919
type Props = MaskedTextInputProps & {
2020
controlled?: boolean;
@@ -33,7 +33,7 @@ const TextInput: FC<Props> = (props) => {
3333
...rest
3434
} = props;
3535

36-
const inputRef = React.useRef<RNTextInput>(null);
36+
const inputRef = React.useRef<MaskedTextInputRef>(null);
3737

3838
const [textState, setTextState] = React.useState({
3939
extracted: initialValue || defaultValue,
@@ -73,6 +73,10 @@ const TextInput: FC<Props> = (props) => {
7373
setTextState({ extracted: "", formatted: "" });
7474
}, [controlled]);
7575

76+
const handleSetText = React.useCallback(() => {
77+
inputRef.current?.setText("999999", false);
78+
}, []);
79+
7680
const handleFocusButtonPress = React.useCallback(() => {
7781
inputRef.current?.focus();
7882
}, []);
@@ -103,6 +107,11 @@ const TextInput: FC<Props> = (props) => {
103107
title="Focus text input"
104108
onPress={handleFocusButtonPress}
105109
/>
110+
<Button
111+
style={styles.button}
112+
title={"Set text"}
113+
onPress={handleSetText}
114+
/>
106115
</>
107116
);
108117
};

e2e/.maestro/clear-text.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
appId: "com.maskedtextinputexample"
2+
---
3+
- launchApp
4+
- tapOn:
5+
id: "phone-input"
6+
- tapOn: "+1 (000) 000-0000"
7+
- inputText: 1
8+
- assertVisible: "formatted value +1 ("
9+
- tapOn:
10+
point: "50%,37%"
11+
- tapOn: "Clear text"
12+
- assertVisible: "+1 (000) 000-0000"
13+
- tapOn: "+1 (000) 000-0000"
14+
- inputText: 1
15+
- assertVisible: "formatted value +1 ("

e2e/.maestro/set-text.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
appId: "com.maskedtextinputexample"
2+
---
3+
- launchApp
4+
- tapOn:
5+
id: "phone-input"
6+
- tapOn: "+1 (000) 000-0000"
7+
- tapOn: "Set text"
8+
- assertVisible: "+1 (999) 999"
9+
- assertVisible: "formatted value +1 (999) 999"

package/android/src/main/java/com/maskedtextinput/managers/AdvancedTextInputMaskDecoratorViewManager.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ class AdvancedTextInputMaskDecoratorViewManager(
1818
) : AdvancedTextInputMaskDecoratorViewManagerSpec<AdvancedTextInputMaskDecoratorView>() {
1919
override fun getName() = NAME
2020

21+
override fun setText(
22+
view: AdvancedTextInputMaskDecoratorView,
23+
text: String?,
24+
autocomplete: Boolean,
25+
) {
26+
if (text != null) {
27+
view.setText(text, autocomplete)
28+
}
29+
}
30+
2131
override fun createViewInstance(context: ThemedReactContext) = AdvancedTextInputMaskDecoratorView(context)
2232

2333
@ReactProp(name = "primaryMaskFormat")

package/android/src/main/java/com/maskedtextinput/views/AdvancedTextInputMaskDecoratorView.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,4 +194,16 @@ class AdvancedTextInputMaskDecoratorView(
194194
maskedTextChangeListener?.allowedKeys = allowedKeys
195195
maybeUpdateText()
196196
}
197+
198+
fun setText(
199+
text: String,
200+
autocomplete: Boolean = false,
201+
) {
202+
maskedTextChangeListener?.let {
203+
val prevAutocomplete = it.autocomplete
204+
it.autocomplete = autocomplete
205+
it.setText(text, autocomplete)
206+
it.autocomplete = prevAutocomplete
207+
}
208+
}
197209
}

package/android/src/oldarch/java/com/maskedtextinput/AdvancedTextInputMaskDecoratorViewManagerSpec.kt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,31 @@ abstract class AdvancedTextInputMaskDecoratorViewManagerSpec<T : View> : SimpleV
7575
view: T,
7676
validationRegex: String?,
7777
)
78+
79+
abstract fun setText(
80+
view: T,
81+
text: String?,
82+
autocomplete: Boolean,
83+
)
84+
85+
override fun receiveCommand(
86+
root: T,
87+
commandId: String?,
88+
args: ReadableArray?,
89+
) {
90+
super.receiveCommand(root, commandId, args)
91+
when (commandId) {
92+
SET_TEXT -> {
93+
val text = args?.getString(0)
94+
val autocomplete = args?.getBoolean(1)
95+
if (text != null && autocomplete != null) {
96+
this.setText(root, text, autocomplete)
97+
}
98+
}
99+
}
100+
}
101+
102+
companion object {
103+
const val SET_TEXT = "setText"
104+
}
78105
}

package/ios/AdvancedTextInputMaskDecoratorView.swift

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ class AdvancedTextInputMaskDecoratorView: UIView {
3939
if result.formattedText.string == nextText { return }
4040

4141
let attributedText = NSAttributedString(string: result.formattedText.string)
42+
43+
setText(textField: textField, text: attributedText)
4244
}
4345
}
4446

@@ -166,12 +168,12 @@ class AdvancedTextInputMaskDecoratorView: UIView {
166168
#endif
167169
}
168170

169-
private func getMaskResultForText(text: String) -> Mask.Result? {
171+
private func getMaskResultForText(text: String, autocomplete: Bool = false) -> Mask.Result? {
170172
guard let primaryMask = maskInputListener?.primaryMask else { return nil }
171173
let caretString = CaretString(
172174
string: text,
173175
caretPosition: text.endIndex,
174-
caretGravity: CaretString.CaretGravity.forward(autocomplete: false)
176+
caretGravity: CaretString.CaretGravity.forward(autocomplete: autocomplete)
175177
)
176178
return primaryMask.apply(toText: caretString)
177179
}
@@ -190,19 +192,14 @@ class AdvancedTextInputMaskDecoratorView: UIView {
190192
setText(textField: textField, text: attributedText)
191193
}
192194

193-
@objc private func maybeUpdateText(text: String) {
194-
guard let primaryMask = maskInputListener?.primaryMask else { return }
195+
@objc func maybeUpdateText(text: String, autocomplete _: Bool = false) {
196+
guard (maskInputListener?.primaryMask) != nil else { return }
195197
guard let textField = textField else { return }
196198

197199
if text == textField.attributedText?.string {
198200
return
199201
}
200202

201-
let caretString = CaretString(
202-
string: text,
203-
caretPosition: text.endIndex,
204-
caretGravity: CaretString.CaretGravity.forward(autocomplete: false)
205-
)
206203
guard let result = getMaskResultForText(text: text) else { return }
207204

208205
if text == result.formattedText.string {
@@ -266,6 +263,17 @@ class AdvancedTextInputMaskDecoratorView: UIView {
266263
textFieldDelegate = nil
267264
}
268265

266+
@objc(setMaskedText:autocomplete:)
267+
func setMaskedText(text: NSString, autocomplete: Bool) {
268+
guard let result = getMaskResultForText(text: text as String, autocomplete: autocomplete) else { return }
269+
270+
let attributedText = NSAttributedString(string: result.formattedText.string)
271+
guard let textField = textField else { return }
272+
273+
setText(textField: textField, text: attributedText)
274+
maskInputListener?.notifyOnMaskedTextChangedListeners(forTextInput: textField, result: result)
275+
}
276+
269277
// MARK: - View Lifecycle
270278

271279
override func didMoveToWindow() {

package/ios/AdvancedTextInputMaskDecoratorViewManager.swift

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77

88
import Foundation
9+
import UIKit
910

1011
@objc(AdvancedTextInputMaskDecoratorViewManager)
1112
class AdvancedTextInputMaskDecoratorViewManager: RCTViewManager {
@@ -14,6 +15,20 @@ class AdvancedTextInputMaskDecoratorViewManager: RCTViewManager {
1415
}
1516

1617
override public static func requiresMainQueueSetup() -> Bool {
17-
false
18+
true
19+
}
20+
21+
@objc(setText:text:autocomplete:)
22+
public func setText(_ reactTag: NSNumber, text: NSString, autocomplete: Bool) {
23+
bridge.uiManager.addUIBlock { _, viewRegistry in
24+
guard let view = viewRegistry?[reactTag] as? AdvancedTextInputMaskDecoratorView else {
25+
if RCT_DEBUG == 1 {
26+
print("Invalid view returned from registry, expecting ContainerView")
27+
}
28+
return
29+
}
30+
31+
view.setMaskedText(text: text, autocomplete: autocomplete)
32+
}
1833
}
1934
}

package/ios/AdvancedTextInputViewContainer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,5 @@
3232
- (void)setAffinityCalculationStrategy:(NSInteger)affinityCalculationStrategy;
3333
- (void)setValidationRegex:(NSString *)validationRegex;
3434
- (void)cleanup;
35+
- (void)setMaskedText:(NSString *_Nonnull)text autocomplete:(BOOL)autocomplete;
3536
@end

package/ios/AdvancedtextInputMaskDecoratorView.mm

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,16 @@ - (void)onAdvancedMaskTextChangeWithEventData:(NSDictionary *)eventData
150150
->onAdvancedMaskTextChange(event);
151151
}
152152

153+
- (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args
154+
{
155+
RCTAdvancedTextInputMaskDecoratorViewHandleCommand(self, commandName, args);
156+
}
157+
158+
- (void)setText:(NSString *)text autocomplete:(BOOL)autocomplete
159+
{
160+
[_view setMaskedText:text autocomplete:autocomplete];
161+
}
162+
153163
@end
154164

155165
Class<RCTComponentViewProtocol> AdvancedTextInputMaskDecoratorViewCls(void)

0 commit comments

Comments
 (0)