carbon-react
Version:
A library of reusable React components and an interface for easily building user interfaces based on Flux.
327 lines (259 loc) • 11.8 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _react2 = require('react');
var _react3 = _interopRequireDefault(_react2);
var _babelTransform = require('livereactload/babel-transform');
var _babelTransform2 = _interopRequireDefault(_babelTransform);
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _class, _temp;
var _propTypes = require('prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _classnames = require('classnames');
var _classnames2 = _interopRequireDefault(_classnames);
var _lodash = require('lodash');
var _input = require('./../../utils/decorators/input');
var _input2 = _interopRequireDefault(_input);
var _inputLabel = require('./../../utils/decorators/input-label');
var _inputLabel2 = _interopRequireDefault(_inputLabel);
var _inputValidation = require('./../../utils/decorators/input-validation');
var _inputValidation2 = _interopRequireDefault(_inputValidation);
var _events = require('./../../utils/helpers/events');
var _events2 = _interopRequireDefault(_events);
var _ether = require('./../../utils/ether');
var _tags = require('../../utils/helpers/tags');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var _components = {
GroupedCharacter: {
displayName: 'GroupedCharacter'
}
};
var _livereactloadBabelTransform2 = (0, _babelTransform2.default)({
filename: 'src/components/grouped-character/grouped-character.js',
components: _components,
locals: [],
imports: [_react3.default]
});
function _wrapComponent(id) {
return function (Component) {
return _livereactloadBabelTransform2(Component, id);
};
}
var GroupedCharacter = (0, _input2.default)((0, _inputLabel2.default)((0, _inputValidation2.default)(_wrapComponent('GroupedCharacter')((_temp = _class = function (_React$Component) {
_inherits(GroupedCharacter, _React$Component);
function GroupedCharacter() {
var _ref;
_classCallCheck(this, GroupedCharacter);
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
var _this = _possibleConstructorReturn(this, (_ref = GroupedCharacter.__proto__ || Object.getPrototypeOf(GroupedCharacter)).call.apply(_ref, [this].concat(args)));
_this.adjustForSeparator = function (leftPosition) {
return _this.isBackspaceKey() ? leftPosition : _this.lastPosition + 1;
};
_this.calculateMaxLength = function () {
return (0, _lodash.sum)(_this.props.groups) + _this.props.groups.length - 1;
};
_this.deleteAfterSeparator = function (value) {
var upToSeparator = _this.sliceUpToSeparator();
return value.slice(0, upToSeparator) + value.slice(upToSeparator + 1);
};
_this.deletingBeforeSeparator = function () {
return _this.isDeleteKey() && (0, _lodash.includes)(_this.insertionIndices, _this.lastPosition);
};
_this.enforceMaxLength = function (value) {
return value.slice(0, _this.maxLength);
};
_this.insertionIndices = function () {
var indices = [_this.props.groups[0]];
for (var i = 1; i < _this.props.groups.length; i++) {
indices.push(indices[i - 1] + _this.props.groups[i] + 1);
}
return indices;
};
_this.isValidKeypress = function (ev) {
return !_events2.default.isNumberKey(ev) && !_events2.default.isAlphabetKey(ev) && !_events2.default.isTabKey(ev) && !_events2.default.isDeleteKey(ev) && !_events2.default.isBackspaceKey(ev) && !_events2.default.isNavigationKey(ev);
};
_this.removeSeparators = function (value) {
return value.replace(/\W/g, '');
};
_this.separatorsNotNeeded = function (plainValue) {
return plainValue.length < _this.insertionIndices[0];
};
_this.setVisibleValue = function (plainValue) {
// return early if no separators needed yet
if (_this.separatorsNotNeeded(plainValue)) {
return plainValue;
}
var valueWithSeparators = (0, _ether.insertAt)(plainValue, { insertionIndices: _this.insertionIndices, separator: _this.props.separator });
// ensure extra characters removed e.g. if long value pasted in field
return _this.enforceMaxLength(valueWithSeparators);
};
_this.state = {};
_this.state.value = _this.props.value;
_this.maxLength = _this.calculateMaxLength();
_this.insertionIndices = _this.insertionIndices();
_this.onKeyDown = _this.onKeyDown.bind(_this);
_this.onChange = _this.onChange.bind(_this);
_this.getCursorPosition = _this.getCursorPosition.bind(_this);
_this.getNewPosition = _this.getNewPosition.bind(_this);
_this.sliceUpToSeparator = _this.sliceUpToSeparator.bind(_this);
_this.getPlainValue = _this.getPlainValue.bind(_this); // value without separators
_this.lastPosition = 0; // last position of cursor 1-indexed
_this.keyPressed = { which: null }; // track key pressed outside of React synthetic event
return _this;
}
_createClass(GroupedCharacter, [{
key: 'componentDidUpdate',
value: function componentDidUpdate() {
var newPosition = this.getCursorPosition();
this._input.setSelectionRange(newPosition, newPosition);
}
// delete value after separator
}, {
key: 'getCursorPosition',
// Handle placement of cursor after updating value
value: function getCursorPosition() {
// Leave cursor in place if deleting
if (this.isDeleteKey()) {
return this.lastPosition;
}
return this.getNewPosition();
}
}, {
key: 'getNewPosition',
value: function getNewPosition() {
var leftPosition = this.lastPosition - 1;
// adjust position for presence of separator
if ((0, _lodash.includes)(this.insertionIndices, leftPosition)) {
// move cursor 1 space left if backspacing character
return this.adjustForSeparator(leftPosition);
}
return this.lastPosition;
}
}, {
key: 'getPlainValue',
value: function getPlainValue(ev) {
var plainValue = this.removeSeparators(ev.target.value);
// Handle deleting to the left of a separator
if (this.deletingBeforeSeparator()) {
plainValue = this.deleteAfterSeparator(plainValue);
}
return plainValue;
}
// Get indices at which to insert separator
}, {
key: 'isBackspaceKey',
value: function isBackspaceKey() {
return _events2.default.isBackspaceKey(this.keyPressed);
}
}, {
key: 'isDeleteKey',
value: function isDeleteKey() {
return _events2.default.isDeleteKey(this.keyPressed);
}
// update value with separators and truncate value if beyond max length
}, {
key: 'sliceUpToSeparator',
//gets value up to separator for current group
value: function sliceUpToSeparator() {
var upToSeparator = 1;
for (var i = 0; i < this.insertionIndices.length; i++) {
if (this.lastPosition < this.insertionIndices[i + 1]) {
upToSeparator = this.lastPosition - i;
break;
}
}
return upToSeparator;
}
}, {
key: 'onChange',
value: function onChange(ev) {
this.lastPosition = ev.target.selectionEnd;
var plainValue = this.getPlainValue(ev),
visibleValue = this.setVisibleValue(plainValue);
this.setState({ value: visibleValue });
this._hidden.value = plainValue;
this._handleOnChange({ target: this._hidden });
}
}, {
key: 'onKeyDown',
value: function onKeyDown(ev) {
// React performs event pooling so can't store event for later reuse easily.
this.keyPressed = { which: ev.which };
if (this.isValidKeypress(ev)) {
ev.preventDefault();
}
}
}, {
key: 'render',
value: function render() {
return _react3.default.createElement(
'div',
_extends({ className: this.mainClasses }, (0, _tags.tagComponent)('grouped-character', this.props)),
this.labelHTML,
this.inputHTML,
_react3.default.createElement('input', this.hiddenInputProps),
this.validationHTML,
this.fieldHelpHTML
);
}
}, {
key: 'inputProps',
get: function get() {
var _validProps = (0, _ether.validProps)(this),
props = _objectWithoutProperties(_validProps, []);
props.className = this.inputClasses;
props.onChange = this.onChange;
props.maxLength = this.maxLength;
props.onKeyDown = this.onKeyDown;
props.style = { width: this.props.inputWidth + 'px' };
props.value = this.state.value;
return props;
}
}, {
key: 'hiddenInputProps',
get: function get() {
var _this2 = this;
return {
value: this.props.value,
ref: function ref(c) {
_this2._hidden = c;
},
type: 'hidden',
readOnly: true,
'data-element': 'hidden-input'
};
}
}, {
key: 'mainClasses',
get: function get() {
return (0, _classnames2.default)(this.props.className, 'carbon-grouped-character');
}
}, {
key: 'inputClasses',
get: function get() {
return 'carbon-grouped-character__input';
}
}]);
return GroupedCharacter;
}(_react3.default.Component), _class.propTypes = {
groups: _propTypes2.default.array.isRequired, // an array of group sizes
inputWidth: _propTypes2.default.string, // pixel value that sets inputWidth
separator: function separator(props, propName, componentName) {
// a separator character to insert between number groups
if (props[propName].length > 1 || typeof props[propName] !== 'string') {
return new Error('Invalid prop ' + propName + ' supplied to ' + componentName + '. Must be string of length 1.');
}
}
}, _class.defaultProps = {
separator: '-',
value: ''
}, _temp)))));
exports.default = GroupedCharacter;