react-native-smooth-pincode-input icon indicating copy to clipboard operation
react-native-smooth-pincode-input copied to clipboard

Updating value of the pincode-input

Open cryptoalex opened this issue 6 years ago • 7 comments

Let's say we need to set a value of pincode-input if the value was received from some source (e.g. in Android - via otp-verify logic).

Getting selection error (4 is codeLength) from the TextInput:

setSpan (4 ... 4) ends beyond length 0

cryptoalex avatar Jan 10 '19 18:01 cryptoalex

The same problem(

vdanylov avatar Jan 31 '19 13:01 vdanylov

same here

hamam99 avatar Feb 15 '19 08:02 hamam99

Any solutions to this?

kwedsd avatar Feb 16 '19 05:02 kwedsd

Nope

hamam99 avatar Feb 16 '19 05:02 hamam99

Use this code

<SmoothPinCodeInput codeLength={6} cellSize={50} cellSpacing={10} textStyle={{ color: 'white', fontSize: FONTSIZE.FONT_25, fontFamily: FONTFAMILY.SEMIBOLD, }} textStyleFocused={{ color: '#ff8b00' }} cellStyle={{ borderBottomWidth: 2, borderColor: 'gray', }} cellStyleFocused={{ borderColor: '#06A8CE', }} placeholder={'*'} value={component.state.code} filledData = {"123734"} onTextChange={code => component.setState({ code })} onFulfill={(code) => component._checkCode(code)} keyboardType={'number-pad'} />

`import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { View, Text, TextInput, StyleSheet, ViewPropTypes, } from 'react-native'; import * as Animatable from 'react-native-animatable';

const styles = StyleSheet.create({ containerDefault: {}, cellDefault: { borderColor: 'gray', borderWidth: 1, }, cellFocusedDefault: { borderColor: 'black', borderWidth: 2, }, textStyleDefault: { color: 'gray', fontSize: 24, }, textStyleFocusedDefault: { color: 'black', }, });

class SmoothPinCodeInput extends Component {

state = { maskDelay: false, focused: false, }; ref = React.createRef(); inputRef = React.createRef();

shake = () => { return this.ref.current.shake(650); };

focus = () => { return this.inputRef.current.focus(); };

blur = () => { return this.inputRef.current.blur(); };

_inputCode = (code) => { const { password, codeLength = 4, onTextChange, onFulfill } = this.props;

if (onTextChange) {
  onTextChange(code);
}
if (code.length === codeLength && onFulfill) {
  onFulfill(code);
}

// handle password mask
const maskDelay = password &&
  code.length - 1 > this.props.value.length; // only when input new char
this.setState({ maskDelay });

if (maskDelay) { // mask password after delay
  setTimeout(() => this.setState({ maskDelay: false }), 200);
}

};

_keyPress = (event) => { if (event.nativeEvent.key === 'Backspace') { const { value, onBackspace } = this.props; if (value === '' && onBackspace) { onBackspace(); } } };

_onFocused = (focused) => { this.setState({ focused }); };

render() { const { value, codeLength, cellSize, cellSpacing, placeholder, password, mask, autoFocus, containerStyle, cellStyle, cellStyleFocused, cellStyleFilled, textStyle, textStyleFocused, keyboardType, animationFocused, } = this.props; const { maskDelay, focused } = this.state; return ( <Animatable.View ref={this.ref} style={[{ alignItems: 'stretch', flexDirection: 'row', justifyContent: 'center', position: 'relative', width: cellSize * codeLength + cellSpacing * (codeLength - 1), height: cellSize, }, containerStyle, ]}> <View style={{ position: 'absolute', margin: 0, height: '100%', flexDirection: 'row', alignItems: 'center', }}> {

        Array.apply(null, Array(codeLength)).map((_, idx) => {
          let value = this.props.filledData
          const cellFocused = focused && idx === value.length;
          const filled = idx < value.length;
          const last = (idx === value.length - 1);

          return (
            <Animatable.View
              key={idx}
              style={[
                {
                  width: cellSize,
                  height: cellSize,
                  marginLeft: cellSpacing / 2,
                  marginRight: cellSpacing / 2,
                  flexDirection: 'row',
                  alignItems: 'center',
                  justifyContent: 'center',
                },
                cellStyle,
                cellFocused ? cellStyleFocused : {},
                filled ? cellStyleFilled : {},
              ]}
              animation={idx === value.length && focused ? animationFocused : null}
              iterationCount="infinite"
              duration={500}
            >
              {(filled || placeholder !== null) && (<Text
                style={[
                  textStyle,
                  cellFocused ? textStyleFocused : {},
                ]}>
                {filled && (password && (!maskDelay || !last)) ? mask : value.charAt(idx)}
                {!filled && placeholder}
              </Text>)}
            </Animatable.View>
          );
        })
      }
    </View>
    <TextInput
      value={value}
      ref={this.inputRef}
      onChangeText={this._inputCode}
      onKeyPress={this._keyPress}
      onFocus={() => this._onFocused(true)}
      onBlur={() => this._onFocused(false)}
      spellCheck={false}
      autoFocus={autoFocus}
      keyboardType={keyboardType}
      numberOfLines={1}
      maxLength={codeLength}
      selection={{
        start: value.length,
        end: value.length,
      }}
      style={{
        flex: 1,
        opacity: 0,
        textAlign: 'center',
      }} />
  </Animatable.View>
);

}

static defaultProps = { value: '', filledData : "", codeLength: 4, cellSize: 48, cellSpacing: 4, placeholder: '', password: false, mask: '*', keyboardType: 'numeric', autoFocus: false, containerStyle: styles.containerDefault, cellStyle: styles.cellDefault, cellStyleFocused: styles.cellFocusedDefault, textStyle: styles.textStyleDefault, textStyleFocused: styles.textStyleFocusedDefault, animationFocused: 'pulse', }; }

SmoothPinCodeInput.propTypes = { value: PropTypes.string, filledData: PropTypes.string, codeLength: PropTypes.number, cellSize: PropTypes.number, cellSpacing: PropTypes.number,

placeholder: PropTypes.string, mask: PropTypes.string, password: PropTypes.bool,

autoFocus: PropTypes.bool,

containerStyle: ViewPropTypes.style,

cellStyle: ViewPropTypes.style, cellStyleFocused: ViewPropTypes.style,

textStyle: Text.propTypes.style, textStyleFocused: Text.propTypes.style,

animationFocused: PropTypes.oneOfType([ PropTypes.string, PropTypes.object, ]),

onFulfill: PropTypes.func, onChangeText: PropTypes.func, onBackspace: PropTypes.func,

keyboardType: PropTypes.string, };

export default SmoothPinCodeInput; `

anandrms4u avatar Jun 27 '19 13:06 anandrms4u

In case somebody stumbles upon this...

This is a react native bug that is likely to be fixed in 0.60. For now I was able to make it work like so: https://gist.github.com/fgreinus/2f62f52a79f98afe43bde5d3b1b6de92

Note: I removed the selection prop in the render method and set the selection prop manually on componentDidUpdate. Really ugly fix, but works for now.

Also, the react native issue for the bug: https://github.com/facebook/react-native/issues/18316

fgreinus avatar Jul 02 '19 15:07 fgreinus

Changing default value from number to string did the trick.

mrruby avatar Jul 15 '19 10:07 mrruby