|

   Veteran Tools Platform - Developer Documentation

There are no notes for this item.

PropRequired?TypeDefaultDescription
multiple No bool false
buttonText No union 'Add Files'
additionalClass No string
additionalErrorClass No string
triggerClass No string
onChange Yes func
accept No string
name Yes string
errorMessage No string
mimeTypes No string ''
<div id="reactMount" data-tpl="errorablefileinput">
    <div>
        <div class="usa-input-error" role="alert"><label class="usa-input-error-label" for="errorable-file-input-35"></label><span class="usa-input-error-message undefined" role="alert" id="errorable-file-input-35-error-message"><span class="sr-only">Error</span> Error message</span><label role="button"
                tabindex="0" for="errorable-file-input-35" class="usa-button usa-button-secondary">Upload some files</label><input type="file" multiple="" style="display:none;" accept="String" id="errorable-file-input-35" name="Name" /></div>
    </div>
</div>
<script>
    window.currentProps = {
        "package": {
            "name": "department-of-veteran-affairs/jean-pants",
            "version": "0.1.0"
        },
        "assetPath": "/design-system/",
        "isProduction": true,
        "componentSourcePath": "./ErrorableFileInput.jsx",
        "name": "Name",
        "multiple": true,
        "buttonText": "Upload some files",
        "accept": "String",
        "errorMessage": "Error message"
    }
</script>
import React from 'react';
import ErrorableFileInput from './ErrorableFileInput';

export default function ErrorableFileInputExample(props) {
  return (
    <ErrorableFileInput
      name={props.name}
      multiple={props.multiple}
      buttonText={props.buttonText}
      accept={props.accept}
      errorMessage={props.errorMessage}
      onChange={(e) => e}/>
  );
}
package:
  name: department-of-veteran-affairs/jean-pants
  version: 0.1.0
assetPath: /design-system/
isProduction: true
componentSourcePath: ./ErrorableFileInput.jsx
name: Name
multiple: true
buttonText: Upload some files
accept: String
errorMessage: Error message
  • Content:
    /* eslint-disable jsx-a11y/no-noninteractive-element-to-interactive-role */
    import PropTypes from 'prop-types';
    import React from 'react';
    import _ from 'lodash';
    
    class ErrorableFileInput extends React.Component {
      constructor() {
        super();
        this.handleChange = this.handleChange.bind(this);
      }
    
      componentWillMount() {
        this.inputId = _.uniqueId('errorable-file-input-');
      }
    
      handleChange(domEvent) {
        this.props.onChange(domEvent.target.files);
        // clear the original input, otherwise events will be triggered
        // with empty file arrays and sometimes uploading a file twice will
        // not work
        domEvent.target.value = null; // eslint-disable-line no-param-reassign
      }
    
      render() {
        let errorSpan = '';
        let errorSpanId = undefined;
        let inputErrorClass = undefined;
        let labelErrorClass = undefined;
    
        if (this.props.errorMessage) {
          errorSpanId = `${this.inputId}-error-message`;
          errorSpan = (
            <span className={`usa-input-error-message ${this.props.additionalErrorClass}`} role="alert" id={errorSpanId}>
              <span className="sr-only">Error</span> {this.props.errorMessage}
            </span>
          );
          inputErrorClass = 'usa-input-error';
          labelErrorClass = 'usa-input-error-label';
        }
    
        // Calculate required
        let requiredSpan = undefined;
        if (this.props.required) {
          requiredSpan = <span className="form-required-span">*</span>;
        }
    
        return (
          <div className={this.props.additionalClass}>
            <div className={inputErrorClass} role="alert">
              <label
                className={labelErrorClass}
                htmlFor={this.inputId}>
                {this.props.label}
                {requiredSpan}
              </label>
              {errorSpan}
              <label
                role="button"
                tabIndex="0"
                htmlFor={this.inputId}
                aria-describedby={this.props['aria-describedby']}
                className={this.props.triggerClass || 'usa-button usa-button-secondary'}>
                {this.props.buttonText}
              </label>
              <input
                multiple={this.props.multiple}
                style={{ display: 'none' }}
                type="file"
                accept={this.props.accept}
                id={this.inputId}
                name={this.props.name}
                onChange={this.handleChange}/>
            </div>
          </div>
        );
      }
    }
    
    ErrorableFileInput.propTypes = {
      /* accepts multiple files */
      multiple: PropTypes.bool,
    
      /* label for the button */
      buttonText: PropTypes.oneOfType([
        PropTypes.string,
        PropTypes.element]),
    
      /* additional CSS classes */
      additionalClass: PropTypes.string,
      additionalErrorClass: PropTypes.string,
      triggerClass: PropTypes.string,
    
      /* function to handle interaction */
      onChange: PropTypes.func.isRequired,
    
      /* ? */
      accept: PropTypes.string,
    
      /* input name */
      name: PropTypes.string.isRequired,
    
      /* message for error state */
      errorMessage: PropTypes.string,
    
      /* file types */
      mimeTypes: PropTypes.string,
    
    };
    
    ErrorableFileInput.defaultProps = {
      buttonText: 'Add Files',
      mimeTypes: '',
      multiple: false
    };
    
    export default ErrorableFileInput;
    
  • URL: /components/raw/errorablefileinput/ErrorableFileInput.jsx
  • Filesystem Path: src/components/form/controls/ErrorableFileInput/ErrorableFileInput.jsx
  • Size: 3.2 KB
  • Content:
    import React from 'react';
    import { shallow } from 'enzyme';
    import { axeCheck } from '../../../../../lib/testing/helpers';
    import { expect } from 'chai';
    import sinon from 'sinon';
    
    import ErrorableFileInput from './ErrorableFileInput';
    
    describe('<ErrorableFileInput>', () => {
      it('no error styles when errorMessage undefined', () => {
        const tree = shallow(
          <ErrorableFileInput buttonText="my label" onChange={(_update) => {}}/>
        );
    
        // No error classes.
        expect(tree.find('.usa-input-error')).to.have.lengthOf(0);
        expect(tree.find('.usa-input-error-label')).to.have.lengthOf(0);
        expect(tree.find('.usa-input-error-message')).to.have.lengthOf(0);
      });
    
      it('has error styles when errorMessage is set', () => {
        const tree = shallow(
          <ErrorableFileInput buttonText="my label" errorMessage="error message" onChange={(_update) => {}}/>
        );
    
        expect(tree.find('.usa-input-error-message').text()).to.equal('Error error message');
      });
    
      it('onChange fires and clears input', () => {
        const onChange = sinon.spy();
        const tree = shallow(
          <ErrorableFileInput buttonText="my label" onChange={onChange}/>
        );
    
        const event = {
          target: {
            files: [{}],
            value: 'asdfasdf'
          }
        };
    
        tree.instance().handleChange(event);
    
        expect(onChange.called).to.be.true;
        expect(event.target.value).to.be.null;
      });
    
      it('passes aXe check', () => {
        const check = axeCheck(<ErrorableFileInput buttonText="my label"/>);
        return check;
      });
    });
    
  • URL: /components/raw/errorablefileinput/ErrorableFileInput.unit.spec.jsx
  • Filesystem Path: src/components/form/controls/ErrorableFileInput/ErrorableFileInput.unit.spec.jsx
  • Size: 1.5 KB
  • Handle: @errorablefileinput
  • Preview:
  • Filesystem Path: src/components/form/controls/ErrorableFileInput/ErrorableFileInput.njk