react-native-controlled-input 0.4.0 → 0.8.0
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/android/src/main/java/com/controlledinput/JetpackComposeView.kt +6 -6
- package/ios/ControlledInputView.mm +17 -1
- package/ios/RNControlledInput.swift +97 -26
- package/lib/module/index.js +10 -2
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/index.tsx +22 -2
|
@@ -87,12 +87,12 @@ fun JetpackComposeView(
|
|
|
87
87
|
val fontSize = style?.fontSize?.let { it.sp } ?: 24.sp
|
|
88
88
|
val fontFamily = remember(style?.fontFamily) {
|
|
89
89
|
style?.fontFamily?.let { name ->
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
90
|
+
try {
|
|
91
|
+
val typeface = com.facebook.react.views.text.ReactFontManager.getInstance()
|
|
92
|
+
.getTypeface(name, Typeface.NORMAL, context.assets)
|
|
93
|
+
typeface?.let { FontFamily(it) }
|
|
94
|
+
} catch (_: Exception) {
|
|
95
|
+
null
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
}
|
|
@@ -10,12 +10,13 @@
|
|
|
10
10
|
#import <React/RCTFabricComponentsPlugins.h>
|
|
11
11
|
|
|
12
12
|
#import <react/renderer/components/ControlledInputViewSpec/ComponentDescriptors.h>
|
|
13
|
+
#import <react/renderer/components/ControlledInputViewSpec/EventEmitters.h>
|
|
13
14
|
#import <react/renderer/components/ControlledInputViewSpec/Props.h>
|
|
14
15
|
#import <react/renderer/components/ControlledInputViewSpec/RCTComponentViewHelpers.h>
|
|
15
16
|
|
|
16
17
|
using namespace facebook::react;
|
|
17
18
|
|
|
18
|
-
@interface ControlledInputView () <RCTControlledInputViewViewProtocol>
|
|
19
|
+
@interface ControlledInputView () <RCTControlledInputViewViewProtocol, RNControlledInputDelegate>
|
|
19
20
|
@end
|
|
20
21
|
|
|
21
22
|
@implementation ControlledInputView {
|
|
@@ -34,6 +35,7 @@ using namespace facebook::react;
|
|
|
34
35
|
_props = defaultProps;
|
|
35
36
|
|
|
36
37
|
_inputView = [[RNControlledInput alloc] initWithFrame:self.bounds];
|
|
38
|
+
_inputView.delegate = self;
|
|
37
39
|
|
|
38
40
|
self.contentView = _inputView;
|
|
39
41
|
}
|
|
@@ -109,4 +111,18 @@ using namespace facebook::react;
|
|
|
109
111
|
[super handleCommand:commandName args:args];
|
|
110
112
|
}
|
|
111
113
|
|
|
114
|
+
- (void)controlledInputDidChangeText:(RNControlledInput *)input value:(NSString *)value
|
|
115
|
+
{
|
|
116
|
+
if (_eventEmitter == nullptr) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const auto eventEmitter = std::static_pointer_cast<const ControlledInputViewEventEmitter>(_eventEmitter);
|
|
121
|
+
const char *utf8Value = value.UTF8String ?: "";
|
|
122
|
+
|
|
123
|
+
eventEmitter->onTextChange(ControlledInputViewEventEmitter::OnTextChange {
|
|
124
|
+
.value = std::string(utf8Value),
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
112
128
|
@end
|
|
@@ -1,49 +1,120 @@
|
|
|
1
1
|
import UIKit
|
|
2
2
|
|
|
3
|
+
@objc public protocol RNControlledInputDelegate: AnyObject {
|
|
4
|
+
func controlledInputDidChangeText(_ input: RNControlledInput, value: String)
|
|
5
|
+
}
|
|
6
|
+
|
|
3
7
|
@objc(RNControlledInput)
|
|
4
|
-
public class RNControlledInput: UIView {
|
|
5
|
-
|
|
8
|
+
public class RNControlledInput: UIView, UITextFieldDelegate {
|
|
9
|
+
|
|
10
|
+
private let textField = UITextField()
|
|
11
|
+
@objc public weak var delegate: RNControlledInputDelegate?
|
|
12
|
+
|
|
6
13
|
@objc public var value: String? {
|
|
7
14
|
didSet {
|
|
8
|
-
|
|
15
|
+
if textField.text != value {
|
|
16
|
+
textField.text = value
|
|
17
|
+
}
|
|
9
18
|
}
|
|
10
19
|
}
|
|
11
|
-
|
|
12
|
-
@objc public var textColor: UIColor?
|
|
13
|
-
@objc public var fontSize: CGFloat = 16
|
|
14
|
-
@objc public var fontFamily: String?
|
|
15
|
-
@objc public var inputHeight: CGFloat = 0
|
|
16
|
-
@objc public var padding: UIEdgeInsets = .zero
|
|
17
|
-
@objc public var borderWidth: CGFloat = 0
|
|
18
|
-
@objc public var borderRadius: CGFloat = 0
|
|
19
|
-
@objc public var borderColor: UIColor?
|
|
20
20
|
|
|
21
|
-
public
|
|
22
|
-
|
|
21
|
+
@objc public var textColor: UIColor? {
|
|
22
|
+
didSet { textField.textColor = textColor }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@objc public var fontSize: CGFloat = 16 {
|
|
26
|
+
didSet { applyFont() }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@objc public var fontFamily: String? {
|
|
30
|
+
didSet { applyFont() }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@objc public var inputHeight: CGFloat = 0 {
|
|
34
|
+
didSet { invalidateIntrinsicContentSize() }
|
|
23
35
|
}
|
|
24
36
|
|
|
37
|
+
@objc public var padding: UIEdgeInsets = .zero {
|
|
38
|
+
didSet { applyPadding() }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@objc public var borderWidth: CGFloat = 0 {
|
|
42
|
+
didSet { layer.borderWidth = borderWidth }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@objc public var borderRadius: CGFloat = 0 {
|
|
46
|
+
didSet { layer.cornerRadius = borderRadius }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@objc public var borderColor: UIColor? {
|
|
50
|
+
didSet { layer.borderColor = borderColor?.cgColor }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public override var canBecomeFirstResponder: Bool { true }
|
|
54
|
+
|
|
25
55
|
@objc public func focus() {
|
|
26
|
-
|
|
27
|
-
_ = becomeFirstResponder()
|
|
56
|
+
textField.becomeFirstResponder()
|
|
28
57
|
}
|
|
29
58
|
|
|
30
59
|
@objc public func blur() {
|
|
31
|
-
|
|
32
|
-
_ = resignFirstResponder()
|
|
60
|
+
textField.resignFirstResponder()
|
|
33
61
|
}
|
|
34
62
|
|
|
35
63
|
@objc public override init(frame: CGRect) {
|
|
36
64
|
super.init(frame: frame)
|
|
37
|
-
|
|
38
|
-
self.translatesAutoresizingMaskIntoConstraints = false
|
|
39
|
-
|
|
40
|
-
NSLayoutConstraint.activate([
|
|
41
|
-
self.widthAnchor.constraint(equalToConstant: 100),
|
|
42
|
-
self.heightAnchor.constraint(equalToConstant: 100)
|
|
43
|
-
])
|
|
65
|
+
setupTextField()
|
|
44
66
|
}
|
|
45
|
-
|
|
67
|
+
|
|
46
68
|
required init?(coder: NSCoder) {
|
|
47
69
|
fatalError("init(coder:) has not been implemented")
|
|
48
70
|
}
|
|
71
|
+
|
|
72
|
+
private func setupTextField() {
|
|
73
|
+
textField.translatesAutoresizingMaskIntoConstraints = false
|
|
74
|
+
textField.borderStyle = .none
|
|
75
|
+
textField.delegate = self
|
|
76
|
+
addSubview(textField)
|
|
77
|
+
|
|
78
|
+
NSLayoutConstraint.activate([
|
|
79
|
+
textField.topAnchor.constraint(equalTo: topAnchor),
|
|
80
|
+
textField.leadingAnchor.constraint(equalTo: leadingAnchor),
|
|
81
|
+
textField.trailingAnchor.constraint(equalTo: trailingAnchor),
|
|
82
|
+
textField.bottomAnchor.constraint(equalTo: bottomAnchor),
|
|
83
|
+
])
|
|
84
|
+
|
|
85
|
+
applyFont()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
|
|
89
|
+
let currentText = textField.text ?? ""
|
|
90
|
+
guard let stringRange = Range(range, in: currentText) else { return true }
|
|
91
|
+
let newText = currentText.replacingCharacters(in: stringRange, with: string)
|
|
92
|
+
|
|
93
|
+
delegate?.controlledInputDidChangeText(self, value: newText)
|
|
94
|
+
|
|
95
|
+
return false
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private func applyFont() {
|
|
99
|
+
if let family = fontFamily, let font = UIFont(name: family, size: fontSize) {
|
|
100
|
+
textField.font = font
|
|
101
|
+
} else {
|
|
102
|
+
textField.font = UIFont.systemFont(ofSize: fontSize)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
private func applyPadding() {
|
|
107
|
+
// UITextField doesn't have built-in edge insets — wrap with container views
|
|
108
|
+
let leftView = UIView(frame: CGRect(x: 0, y: 0, width: padding.left, height: 1))
|
|
109
|
+
let rightView = UIView(frame: CGRect(x: 0, y: 0, width: padding.right, height: 1))
|
|
110
|
+
textField.leftView = leftView
|
|
111
|
+
textField.leftViewMode = .always
|
|
112
|
+
textField.rightView = rightView
|
|
113
|
+
textField.rightViewMode = .always
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
public override func layoutSubviews() {
|
|
117
|
+
super.layoutSubviews()
|
|
118
|
+
layer.borderColor = borderColor?.cgColor
|
|
119
|
+
}
|
|
49
120
|
}
|
package/lib/module/index.js
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import { forwardRef, useImperativeHandle, useRef } from 'react';
|
|
4
|
-
import { Platform } from 'react-native';
|
|
4
|
+
import { Platform, processColor } from 'react-native';
|
|
5
5
|
import ControlledInputViewNativeComponent, { Commands } from './ControlledInputViewNativeComponent';
|
|
6
6
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
7
|
export const ControlledInputView = /*#__PURE__*/forwardRef((props, ref) => {
|
|
8
8
|
const nativeRef = useRef(null);
|
|
9
|
+
const nativeProps = Platform.OS === 'ios' && props.inputStyle ? {
|
|
10
|
+
...props,
|
|
11
|
+
inputStyle: {
|
|
12
|
+
...props.inputStyle,
|
|
13
|
+
color: props.inputStyle.color == null ? props.inputStyle.color : processColor(props.inputStyle.color),
|
|
14
|
+
borderColor: props.inputStyle.borderColor == null ? props.inputStyle.borderColor : processColor(props.inputStyle.borderColor)
|
|
15
|
+
}
|
|
16
|
+
} : props;
|
|
9
17
|
useImperativeHandle(ref, () => ({
|
|
10
18
|
blur: () => {
|
|
11
19
|
if (!nativeRef.current) {
|
|
@@ -27,7 +35,7 @@ export const ControlledInputView = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
27
35
|
}
|
|
28
36
|
}));
|
|
29
37
|
return /*#__PURE__*/_jsx(ControlledInputViewNativeComponent, {
|
|
30
|
-
...
|
|
38
|
+
...nativeProps,
|
|
31
39
|
ref: nativeRef
|
|
32
40
|
});
|
|
33
41
|
});
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["forwardRef","useImperativeHandle","useRef","Platform","ControlledInputViewNativeComponent","Commands","jsx","_jsx","ControlledInputView","props","ref","nativeRef","
|
|
1
|
+
{"version":3,"names":["forwardRef","useImperativeHandle","useRef","Platform","processColor","ControlledInputViewNativeComponent","Commands","jsx","_jsx","ControlledInputView","props","ref","nativeRef","nativeProps","OS","inputStyle","color","borderColor","blur","current","console","log","focus"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SACEA,UAAU,EACVC,mBAAmB,EACnBC,MAAM,QAED,OAAO;AACd,SAASC,QAAQ,EAAEC,YAAY,QAAQ,cAAc;AACrD,OAAOC,kCAAkC,IACvCC,QAAQ,QAEH,sCAAsC;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAO9C,OAAO,MAAMC,mBAAmB,gBAAGT,UAAU,CAG3C,CAACU,KAAK,EAAEC,GAAG,KAAK;EAChB,MAAMC,SAAS,GACbV,MAAM,CAAwD,IAAI,CAAC;EACrE,MAAMW,WAAW,GACfV,QAAQ,CAACW,EAAE,KAAK,KAAK,IAAIJ,KAAK,CAACK,UAAU,GACrC;IACE,GAAGL,KAAK;IACRK,UAAU,EAAE;MACV,GAAGL,KAAK,CAACK,UAAU;MACnBC,KAAK,EACHN,KAAK,CAACK,UAAU,CAACC,KAAK,IAAI,IAAI,GAC1BN,KAAK,CAACK,UAAU,CAACC,KAAK,GACtBZ,YAAY,CAACM,KAAK,CAACK,UAAU,CAACC,KAAK,CAAC;MAC1CC,WAAW,EACTP,KAAK,CAACK,UAAU,CAACE,WAAW,IAAI,IAAI,GAChCP,KAAK,CAACK,UAAU,CAACE,WAAW,GAC5Bb,YAAY,CAACM,KAAK,CAACK,UAAU,CAACE,WAAW;IACjD;EACF,CAAC,GACDP,KAAK;EAEXT,mBAAmB,CAACU,GAAG,EAAE,OAAO;IAC9BO,IAAI,EAAEA,CAAA,KAAM;MACV,IAAI,CAACN,SAAS,CAACO,OAAO,EAAE;QACtB;MACF;MAEA,IAAIhB,QAAQ,CAACW,EAAE,KAAK,KAAK,IAAIX,QAAQ,CAACW,EAAE,KAAK,SAAS,EAAE;QACtDM,OAAO,CAACC,GAAG,CACT,yBAAyBlB,QAAQ,CAACW,EAAE,yBACtC,CAAC;QACDR,QAAQ,CAACY,IAAI,CAACN,SAAS,CAACO,OAAO,CAAC;MAClC;IACF,CAAC;IACDG,KAAK,EAAEA,CAAA,KAAM;MACX,IAAI,CAACV,SAAS,CAACO,OAAO,EAAE;QACtB;MACF;MAEA,IAAIhB,QAAQ,CAACW,EAAE,KAAK,KAAK,IAAIX,QAAQ,CAACW,EAAE,KAAK,SAAS,EAAE;QACtDM,OAAO,CAACC,GAAG,CACT,yBAAyBlB,QAAQ,CAACW,EAAE,0BACtC,CAAC;QACDR,QAAQ,CAACgB,KAAK,CAACV,SAAS,CAACO,OAAO,CAAC;MACnC;IACF;EACF,CAAC,CAAC,CAAC;EAEH,oBACEX,IAAA,CAACH,kCAAkC;IAAA,GAC7BQ,WAAW;IACfF,GAAG,EAAEC;EAAiB,CACvB,CAAC;AAEN,CAAC,CAAC;AAEF,cAAc,sCAAsC","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAOA,OAA2C,EAEzC,KAAK,WAAW,EACjB,MAAM,sCAAsC,CAAC;AAE9C,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,eAAO,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAOA,OAA2C,EAEzC,KAAK,WAAW,EACjB,MAAM,sCAAsC,CAAC;AAE9C,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,eAAO,MAAM,mBAAmB,gHAyD9B,CAAC;AAEH,cAAc,sCAAsC,CAAC"}
|
package/package.json
CHANGED
package/src/index.tsx
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
useRef,
|
|
5
5
|
type ElementRef,
|
|
6
6
|
} from 'react';
|
|
7
|
-
import { Platform } from 'react-native';
|
|
7
|
+
import { Platform, processColor } from 'react-native';
|
|
8
8
|
import ControlledInputViewNativeComponent, {
|
|
9
9
|
Commands,
|
|
10
10
|
type NativeProps,
|
|
@@ -21,6 +21,23 @@ export const ControlledInputView = forwardRef<
|
|
|
21
21
|
>((props, ref) => {
|
|
22
22
|
const nativeRef =
|
|
23
23
|
useRef<ElementRef<typeof ControlledInputViewNativeComponent>>(null);
|
|
24
|
+
const nativeProps =
|
|
25
|
+
Platform.OS === 'ios' && props.inputStyle
|
|
26
|
+
? {
|
|
27
|
+
...props,
|
|
28
|
+
inputStyle: {
|
|
29
|
+
...props.inputStyle,
|
|
30
|
+
color:
|
|
31
|
+
props.inputStyle.color == null
|
|
32
|
+
? props.inputStyle.color
|
|
33
|
+
: processColor(props.inputStyle.color),
|
|
34
|
+
borderColor:
|
|
35
|
+
props.inputStyle.borderColor == null
|
|
36
|
+
? props.inputStyle.borderColor
|
|
37
|
+
: processColor(props.inputStyle.borderColor),
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
: props;
|
|
24
41
|
|
|
25
42
|
useImperativeHandle(ref, () => ({
|
|
26
43
|
blur: () => {
|
|
@@ -50,7 +67,10 @@ export const ControlledInputView = forwardRef<
|
|
|
50
67
|
}));
|
|
51
68
|
|
|
52
69
|
return (
|
|
53
|
-
<ControlledInputViewNativeComponent
|
|
70
|
+
<ControlledInputViewNativeComponent
|
|
71
|
+
{...nativeProps}
|
|
72
|
+
ref={nativeRef as any}
|
|
73
|
+
/>
|
|
54
74
|
);
|
|
55
75
|
});
|
|
56
76
|
|