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.
@@ -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
- listOf("ttf", "otf").firstNotNullOfOrNull { ext ->
91
- try {
92
- FontFamily(Typeface.createFromAsset(context.assets, "fonts/$name.$ext"))
93
- } catch (_: Exception) {
94
- null
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
- // Update UI
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 override var canBecomeFirstResponder: Bool {
22
- true
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
- print("[ControlledInputView] RNControlledInput.focus()")
27
- _ = becomeFirstResponder()
56
+ textField.becomeFirstResponder()
28
57
  }
29
58
 
30
59
  @objc public func blur() {
31
- print("[ControlledInputView] RNControlledInput.blur()")
32
- _ = resignFirstResponder()
60
+ textField.resignFirstResponder()
33
61
  }
34
62
 
35
63
  @objc public override init(frame: CGRect) {
36
64
  super.init(frame: frame)
37
- self.backgroundColor = .red
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
  }
@@ -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
- ...props,
38
+ ...nativeProps,
31
39
  ref: nativeRef
32
40
  });
33
41
  });
@@ -1 +1 @@
1
- {"version":3,"names":["forwardRef","useImperativeHandle","useRef","Platform","ControlledInputViewNativeComponent","Commands","jsx","_jsx","ControlledInputView","props","ref","nativeRef","blur","current","OS","console","log","focus"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SACEA,UAAU,EACVC,mBAAmB,EACnBC,MAAM,QAED,OAAO;AACd,SAASC,QAAQ,QAAQ,cAAc;AACvC,OAAOC,kCAAkC,IACvCC,QAAQ,QAEH,sCAAsC;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAO9C,OAAO,MAAMC,mBAAmB,gBAAGR,UAAU,CAG3C,CAACS,KAAK,EAAEC,GAAG,KAAK;EAChB,MAAMC,SAAS,GACbT,MAAM,CAAwD,IAAI,CAAC;EAErED,mBAAmB,CAACS,GAAG,EAAE,OAAO;IAC9BE,IAAI,EAAEA,CAAA,KAAM;MACV,IAAI,CAACD,SAAS,CAACE,OAAO,EAAE;QACtB;MACF;MAEA,IAAIV,QAAQ,CAACW,EAAE,KAAK,KAAK,IAAIX,QAAQ,CAACW,EAAE,KAAK,SAAS,EAAE;QACtDC,OAAO,CAACC,GAAG,CACT,yBAAyBb,QAAQ,CAACW,EAAE,yBACtC,CAAC;QACDT,QAAQ,CAACO,IAAI,CAACD,SAAS,CAACE,OAAO,CAAC;MAClC;IACF,CAAC;IACDI,KAAK,EAAEA,CAAA,KAAM;MACX,IAAI,CAACN,SAAS,CAACE,OAAO,EAAE;QACtB;MACF;MAEA,IAAIV,QAAQ,CAACW,EAAE,KAAK,KAAK,IAAIX,QAAQ,CAACW,EAAE,KAAK,SAAS,EAAE;QACtDC,OAAO,CAACC,GAAG,CACT,yBAAyBb,QAAQ,CAACW,EAAE,0BACtC,CAAC;QACDT,QAAQ,CAACY,KAAK,CAACN,SAAS,CAACE,OAAO,CAAC;MACnC;IACF;EACF,CAAC,CAAC,CAAC;EAEH,oBACEN,IAAA,CAACH,kCAAkC;IAAA,GAAKK,KAAK;IAAEC,GAAG,EAAEC;EAAiB,CAAE,CAAC;AAE5E,CAAC,CAAC;AAEF,cAAc,sCAAsC","ignoreList":[]}
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,gHAqC9B,CAAC;AAEH,cAAc,sCAAsC,CAAC"}
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-controlled-input",
3
- "version": "0.4.0",
3
+ "version": "0.8.0",
4
4
  "description": "React Native Controlled Inputative Controlled Input",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
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 {...props} ref={nativeRef as any} />
70
+ <ControlledInputViewNativeComponent
71
+ {...nativeProps}
72
+ ref={nativeRef as any}
73
+ />
54
74
  );
55
75
  });
56
76