diff --git a/packages/core/dist/components/ChoiceList/ChoiceList.js b/packages/core/dist/components/ChoiceList/ChoiceList.js index 96aaea6c99..9d486c3192 100644 --- a/packages/core/dist/components/ChoiceList/ChoiceList.js +++ b/packages/core/dist/components/ChoiceList/ChoiceList.js @@ -144,6 +144,7 @@ var ChoiceList = exports.ChoiceList = function (_React$PureComponent) { }, { key: 'select', value: function select(selectProps, options) { + var classes = this.props.size && 'ds-c-field--' + this.props.size; return _react2.default.createElement( _Select2.default, _extends({ @@ -152,7 +153,8 @@ var ChoiceList = exports.ChoiceList = function (_React$PureComponent) { inversed: this.props.inversed, name: this.props.name, onBlur: this.props.onBlur, - onChange: this.props.onChange + onChange: this.props.onChange, + className: classes }, selectProps), options ); @@ -268,6 +270,10 @@ ChoiceList.propTypes = { name: _propTypes2.default.string.isRequired, onBlur: _propTypes2.default.func, onChange: _propTypes2.default.func, + /** + * If the component renders a select, set the max-width of the input either to `'small'` or `'medium'`. + */ + size: _propTypes2.default.oneOf(['small', 'medium']), /** * You can manually set the `type` if you prefer things to be less magical. * Otherwise, the type will be inferred by the other `props`, based diff --git a/packages/core/dist/components/ChoiceList/Select.js b/packages/core/dist/components/ChoiceList/Select.js index ce03348c6a..86360ae18d 100644 --- a/packages/core/dist/components/ChoiceList/Select.js +++ b/packages/core/dist/components/ChoiceList/Select.js @@ -39,10 +39,11 @@ var Select = function Select(props) { className = props.className, id = props.id, inversed = props.inversed, - selectProps = _objectWithoutProperties(props, ['children', 'className', 'id', 'inversed']); + size = props.size, + selectProps = _objectWithoutProperties(props, ['children', 'className', 'id', 'inversed', 'size']); /* eslint-enable prefer-const */ - var classes = (0, _classnames2.default)('ds-c-field', { 'ds-c-field--inverse': inversed }, className); + var classes = (0, _classnames2.default)('ds-c-field', { 'ds-c-field--inverse': inversed }, className, size && 'ds-c-field--' + size); if (!id) { id = (0, _lodash2.default)('select_' + selectProps.name + '_'); @@ -95,6 +96,10 @@ Select.propTypes = { name: _propTypes2.default.string.isRequired, onBlur: _propTypes2.default.func, onChange: _propTypes2.default.func, + /** + * Set the max-width of the input either to `'small'` or `'medium'`. + */ + size: _propTypes2.default.oneOf(['small', 'medium']), /** * Sets the field's `value`. Use this in combination with `onChange` * for a controlled component; otherwise, set `defaultValue`. diff --git a/packages/core/dist/components/TextField/TextField.js b/packages/core/dist/components/TextField/TextField.js index ad4c21dbfb..d2e82b1873 100644 --- a/packages/core/dist/components/TextField/TextField.js +++ b/packages/core/dist/components/TextField/TextField.js @@ -56,9 +56,60 @@ var TextField = exports.TextField = function (_React$PureComponent) { } _createClass(TextField, [{ + key: 'ariaLabel', + value: function ariaLabel() { + if (this.props.ariaLabel) { + return this.props.ariaLabel; + } else if (this.props.mask === 'currency') { + return this.props.label + '. Enter amount in dollars.'; + } + } + + /** + * @param {React.Component} field + * @returns {React.Component} The input field, optionally including mask + * markup if a mask is present + */ + + }, { + key: 'renderFieldAndMask', + value: function renderFieldAndMask(field) { + var maskName = this.props.mask; + + return maskName ? _react2.default.createElement( + 'div', + { className: 'ds-c-field-mask ds-c-field-mask--' + maskName }, + this.renderMask(), + field + ) : field; + } + + /** + * UI overlayed on top of a field to support certain masks + */ + + }, { + key: 'renderMask', + value: function renderMask() { + if (this.props.mask) { + var content = { + currency: '$' + }; + + return _react2.default.createElement( + 'div', + { + className: 'ds-c-field__before ds-c-field__before--' + this.props.mask + }, + content[this.props.mask] + ); + } + } + }, { key: 'render', value: function render() { var _props = this.props, + ariaLabel = _props.ariaLabel, className = _props.className, labelClassName = _props.labelClassName, fieldClassName = _props.fieldClassName, @@ -68,21 +119,33 @@ var TextField = exports.TextField = function (_React$PureComponent) { requirementLabel = _props.requirementLabel, inversed = _props.inversed, rows = _props.rows, + mask = _props.mask, multiline = _props.multiline, label = _props.label, fieldRef = _props.fieldRef, + size = _props.size, type = _props.type, - fieldProps = _objectWithoutProperties(_props, ['className', 'labelClassName', 'fieldClassName', 'errorMessage', 'hint', 'id', 'requirementLabel', 'inversed', 'rows', 'multiline', 'label', 'fieldRef', 'type']); + fieldProps = _objectWithoutProperties(_props, ['ariaLabel', 'className', 'labelClassName', 'fieldClassName', 'errorMessage', 'hint', 'id', 'requirementLabel', 'inversed', 'rows', 'mask', 'multiline', 'label', 'fieldRef', 'size', 'type']); var FieldComponent = multiline ? 'textarea' : 'input'; var _rows = multiline && rows ? rows : undefined; var classes = (0, _classnames2.default)('ds-u-clearfix', // fixes issue where the label's margin is collapsed className); - var fieldClasses = (0, _classnames2.default)('ds-c-field', { + + var fieldClasses = (0, _classnames2.default)('ds-c-field', mask && 'ds-c-field--' + mask, { 'ds-c-field--error': typeof errorMessage === 'string', 'ds-c-field--inverse': inversed - }, fieldClassName); + }, fieldClassName, size && 'ds-c-field--' + size); + + var field = _react2.default.createElement(FieldComponent, _extends({ + 'aria-label': this.ariaLabel(), + className: fieldClasses, + id: this.id, + ref: fieldRef, + rows: _rows, + type: multiline ? undefined : type + }, fieldProps)); return _react2.default.createElement( 'div', @@ -99,13 +162,7 @@ var TextField = exports.TextField = function (_React$PureComponent) { }, label ), - _react2.default.createElement(FieldComponent, _extends({ - className: fieldClasses, - id: this.id, - ref: fieldRef, - rows: _rows, - type: multiline ? undefined : type - }, fieldProps)) + this.renderFieldAndMask(field, mask) ); } }]); @@ -118,6 +175,11 @@ TextField.defaultProps = { }; TextField.propTypes = { + /** + * Apply an `aria-label` to the text field to provide additional + * context to assistive devices. + */ + ariaLabel: _propTypes2.default.string, /** * Additional classes to be added to the root `div` element */ @@ -161,6 +223,12 @@ TextField.propTypes = { * Additional classes to be added to the label */ labelClassName: _propTypes2.default.string, + /** + * Apply formatting to the field that's unique to the value + * you expect to be entered. Depending on the mask, the + * field's appearance and functionality may be affected. + */ + mask: _propTypes2.default.oneOf(['currency']), /** * `max` HTML input attribute */ @@ -170,7 +238,7 @@ TextField.propTypes = { */ min: _propTypes2.default.oneOfType([_propTypes2.default.number, _propTypes2.default.string]), /** - * Whether or not the textfield is a multiline textfield + * Whether or not the text field is a multiline text field */ multiline: _propTypes2.default.bool, name: _propTypes2.default.string.isRequired, @@ -181,6 +249,10 @@ TextField.propTypes = { * applicable if this is a multiline field. */ rows: _propTypes2.default.oneOfType([_propTypes2.default.number, _propTypes2.default.string]), + /** + * Set the max-width of the input either to `'small'` or `'medium'`. + */ + size: _propTypes2.default.oneOf(['small', 'medium']), /** * Any valid `input` [type](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). */ diff --git a/packages/core/src/components/ChoiceList/ChoiceList.example.jsx b/packages/core/src/components/ChoiceList/ChoiceList.example.jsx index 0a4e985ec8..c1755c09b0 100644 --- a/packages/core/src/components/ChoiceList/ChoiceList.example.jsx +++ b/packages/core/src/components/ChoiceList/ChoiceList.example.jsx @@ -30,6 +30,27 @@ ReactDOM.render( label="Select example" name="select_choices_field" /> + + , document.getElementById('js-example') ); @@ -70,5 +91,6 @@ function choices() { function options() { const options = generateChoices(8); options[1].defaultChecked = true; + console.log(options); return options; } diff --git a/packages/core/src/components/ChoiceList/ChoiceList.jsx b/packages/core/src/components/ChoiceList/ChoiceList.jsx index f39329115f..83aff1088b 100644 --- a/packages/core/src/components/ChoiceList/ChoiceList.jsx +++ b/packages/core/src/components/ChoiceList/ChoiceList.jsx @@ -81,6 +81,7 @@ export class ChoiceList extends React.PureComponent { * @param {array} options - - - - - - - - , +
+ +

Small size modifier

+ +

Medium size modifier

+ +
, document.getElementById('js-example') ); diff --git a/packages/core/src/components/ChoiceList/Select.jsx b/packages/core/src/components/ChoiceList/Select.jsx index 4131da802c..0ef3efb9e5 100644 --- a/packages/core/src/components/ChoiceList/Select.jsx +++ b/packages/core/src/components/ChoiceList/Select.jsx @@ -17,6 +17,7 @@ export const Select = function(props) { className, id, inversed, + size, ...selectProps } = props; /* eslint-enable prefer-const */ @@ -24,7 +25,8 @@ export const Select = function(props) { const classes = classNames( 'ds-c-field', { 'ds-c-field--inverse': inversed }, - className + className, + size && `ds-c-field--${size}` ); if (!id) { @@ -68,9 +70,7 @@ Select.propTypes = { if (props[propName]) { /* eslint-disable quotes */ return new Error( - `'${propName}' supplied to '${ - componentName - }'. [A11Y]: Users often don’t` + + `'${propName}' supplied to '${componentName}'. [A11Y]: Users often don’t` + ` understand how to select multiple items from dropdowns. Use checkboxes instead.` ); /* eslint-enable */ @@ -82,6 +82,10 @@ Select.propTypes = { name: PropTypes.string.isRequired, onBlur: PropTypes.func, onChange: PropTypes.func, + /** + * Set the max-width of the input either to `'small'` or `'medium'`. + */ + size: PropTypes.oneOf(['small', 'medium']), /** * Sets the field's `value`. Use this in combination with `onChange` * for a controlled component; otherwise, set `defaultValue`. diff --git a/packages/core/src/components/ChoiceList/Select.test.jsx b/packages/core/src/components/ChoiceList/Select.test.jsx index c2791cf239..008f8e248c 100644 --- a/packages/core/src/components/ChoiceList/Select.test.jsx +++ b/packages/core/src/components/ChoiceList/Select.test.jsx @@ -90,6 +90,14 @@ describe('Select', () => { expect(data.wrapper.hasClass('ds-c-field')).toBe(true); }); + it('adds size classes to root element', () => { + const mediumData = shallowRender({ size: 'medium' }); + const smallData = shallowRender({ size: 'small' }); + + expect(mediumData.wrapper.hasClass('ds-c-field--medium')).toBe(true); + expect(smallData.wrapper.hasClass('ds-c-field--small')).toBe(true); + }); + it('is disabled', () => { const data = shallowRender({ disabled: true }); diff --git a/packages/core/src/components/TextField/TextField.example.jsx b/packages/core/src/components/TextField/TextField.example.jsx index 40235c19c1..b189a06d1f 100644 --- a/packages/core/src/components/TextField/TextField.example.jsx +++ b/packages/core/src/components/TextField/TextField.example.jsx @@ -11,6 +11,12 @@ ReactDOM.render( name="single_example" requirementLabel="Optional" /> + + First name + + + +