<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import creditCardType, { types as CardType } from 'credit-card-type';

import FormInputHelp from './FormInputHelp';
import FormInputErrors from './FormInputErrors';
import FormInputLabel from './FormInputLabel';

// 19 is the longest length of any
// accepted card type as of July 2017
const FALLBACK_CARD_LENGTH = 19;
const CARD_GAP_STRING = ' ';

export default class FormCreditCardField extends React.PureComponent {
  static propTypes = {
    label: PropTypes.string.isRequired,
    className: PropTypes.string,
    acceptedTypes: PropTypes.arrayOf(
      PropTypes.oneOf(Object.values(CardType))
    ).isRequired,
    name: PropTypes.string,
    defaultValue: PropTypes.string,
    placeholder: PropTypes.string,
    help: PropTypes.string,
    onChange: PropTypes.func,
    disabled: PropTypes.bool,
    errors: PropTypes.array,
    required: PropTypes.bool
  };

  static defaultProps = {
    acceptedTypes: [
      CardType.VISA,
      CardType.MASTERCARD,
      CardType.AMERICAN_EXPRESS
    ]
  };

  state = {
    value: '',
    selectionStart: 0,
    selectionEnd: 0
  }

  // NOTE: We make the input a controlled component within the
  // context of the credit card field so that usages can reset the value
  // via defaultValue without controlling the entire component themselves
  componentWillMount() {
    if (this.props.defaultValue) {
      this.setState({ value: this.props.defaultValue });
    }
  }

  componentDidMount() {
    document.addEventListener('selectionchange', this.handleSelectionChange);
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.defaultValue !== this.props.defaultValue) {
      this.setState({ value: nextProps.defaultValue || '' });
    }
  }

  componentDidUpdate() {
    const { selectionStart, selectionEnd } = this.state;

    // Place the cursor in the right position
    // in the text field, after processing
    //
    // NOTE: This is only done when the input's state
    // isn't what's expected, to avoid triggering weird
    // mouse selection behaviour!
    if (selectionStart !== this.input.selectionStart) {
      this.input.selectionStart = selectionStart;
    }

    if (selectionEnd !== this.input.selectionEnd) {
      this.input.selectionEnd = selectionEnd;
    }
  }

  componentWillUnmount() {
    document.removeEventListener('selectionchange', this.handleSelectionChange);
  }

  render() {
    return (
      <div className="mb2"><commit_msg>Use setSelectionRange, improves iOS behaviour<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import creditCardType, { types as CardType } from 'credit-card-type';

import FormInputHelp from './FormInputHelp';
import FormInputErrors from './FormInputErrors';
import FormInputLabel from './FormInputLabel';

// 19 is the longest length of any
// accepted card type as of July 2017
const FALLBACK_CARD_LENGTH = 19;
const CARD_GAP_STRING = ' ';

export default class FormCreditCardField extends React.PureComponent {
  static propTypes = {
    label: PropTypes.string.isRequired,
    className: PropTypes.string,
    acceptedTypes: PropTypes.arrayOf(
      PropTypes.oneOf(Object.values(CardType))
    ).isRequired,
    name: PropTypes.string,
    defaultValue: PropTypes.string,
    placeholder: PropTypes.string,
    help: PropTypes.string,
    onChange: PropTypes.func,
    disabled: PropTypes.bool,
    errors: PropTypes.array,
    required: PropTypes.bool
  };

  static defaultProps = {
    acceptedTypes: [
      CardType.VISA,
      CardType.MASTERCARD,
      CardType.AMERICAN_EXPRESS
    ]
  };

  state = {
    value: '',
    selectionStart: 0,
    selectionEnd: 0
  }

  // NOTE: We make the input a controlled component within the
  // context of the credit card field so that usages can reset the value
  // via defaultValue without controlling the entire component themselves
  componentWillMount() {
    if (this.props.defaultValue) {
      this.setState({ value: this.props.defaultValue });
    }
  }

  componentDidMount() {
    document.addEventListener('selectionchange', this.handleSelectionChange);
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.defaultValue !== this.props.defaultValue) {
      this.setState({ value: nextProps.defaultValue || '' });
    }
  }

  componentDidUpdate() {
    const { selectionStart, selectionEnd } = this.state;

    // Place the cursor in the right position
    // in the text field, after processing
    //
    // NOTE: This is only done when the input's state
    // isn't what's expected, to avoid triggering weird
    // mouse selection behaviour!
    if (selectionStart !== this.input.selectionStart || selectionEnd !== this.input.selectionEnd) {
      this.input.setSelectionRange(selectionStart, selectionEnd);
    }
  }

  componentWillUnmount() {
    document.removeEventListener('selectionchange', this.handleSelectionChange);
  }

  render() {
    return (
      <div className="mb2">
{'fraction_non_alphanumeric': 0.10033510743150009, 'fraction_numerical': 0.004336684407648335, 'mean_word_length': 3.4744268077601412, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4813623', 'n_tokens_mistral': 1427, 'n_tokens_neox': 1406, 'n_words': 390}