2 * Copyright 2015-present Greg Hurrell. All rights reserved.
3 * Licensed under the terms of the MIT license.
10 import DIGITS from './DIGITS';
11 import React from 'react';
12 import convert from './convert';
13 import cx from 'classnames';
19 export const ValuePropType = React.PropTypes.shape({
20 base: React.PropTypes.number,
21 value: React.PropTypes.string,
25 * Convert from `value` to `base`.
27 function fromValue(value: ?Value, base: number): string {
30 } else if (value.base === base) {
33 return convert(value.value, value.base, base);
36 export default class Field extends React.Component {
38 base: React.PropTypes.number,
39 onValueChange: React.PropTypes.func.required,
42 static defaultProps = {
48 if (props.base < 2 || props.base > DIGITS.length) {
50 `base prop must be between 2..${DIGITS.length}`
53 this.state = {copySucceeded: false};
56 _isValid(value: string): boolean {
57 const validator = new RegExp(
58 `^[${DIGITS.slice(0, this.props.base)}]*$`
60 return validator.test(value.trim().toLowerCase());
63 _onChange = event => {
64 const value = event.currentTarget.value;
65 if (this._isValid(value)) {
66 this.props.onValueChange({
67 base: this.props.base,
74 React.findDOMNode(this._input).select();
76 // May throw a SecurityError.
79 copySucceeded: document.execCommand('copy'),
81 setTimeout(() => this.setState({copySucceeded: false}), 750);
82 } catch(error) { // eslint-disable-line no-empty
84 this.setState({copySucceeded: false});
89 // Would check `document.queryCommandSupported('copy')` here, but that
91 // - https://code.google.com/p/chromium/issues/detail?id=476508
92 // - https://github.com/w3c/clipboard-apis/issues/4
95 className="hextrapolate-copy"
96 onClick={this._onCopy}
97 title="Copy to Clipboard">
104 const classNames = cx({
105 'hextrapolate-copy-status': true,
106 'hextrapolate-copy-success': this.state.copySucceeded,
108 return <span className={classNames}>✓</span>;
112 React.findDOMNode(this._input).focus();
117 <span className="hextrapolate-field">
119 onChange={this._onChange}
120 ref={ref => this._input = ref}
122 value={fromValue(this.props.value, this.props.base)}