|

   Veteran Tools Platform - Developer Documentation

There are no notes for this item.

PropRequired?TypeDefaultDescription
buttonText Yes string
clickHandler Yes func
cssClass No string
contents Yes node
icon No node
id No string
isOpen Yes bool
disabled No bool false
container No union root.document
<div id="reactMount" data-tpl="dropdownpanel">
    <div class="va-dropdown"><button class="va-dropdown va-dropdown-trigger" aria-expanded="true"><span>Helpdesk</span></button>
        <div class="va-dropdown-panel">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce ullamcorper at eros eu suscipit. Ut imperdiet libero et luctus pretium.</div>
    </div>
</div>
<script>
    window.currentProps = {
        "package": {
            "name": "department-of-veteran-affairs/jean-pants",
            "version": "0.1.0"
        },
        "assetPath": "/design-system/",
        "isProduction": true,
        "componentSourcePath": "./DropDownPanel.jsx",
        "id": "default",
        "buttonText": "Helpdesk",
        "cssClass": "va-dropdown",
        "isOpen": true,
        "contents": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce ullamcorper at eros eu suscipit. Ut imperdiet libero et luctus pretium."
    }
</script>
import React from 'react';
import DropDownPanel from './DropDownPanel';

export default function DropDownPanelExample(props) {
  return (
    <DropDownPanel
      buttonText={props.buttonText}
      cssClass={props.cssClass}
      isOpen={props.isOpen}
      contents={props.contents}
      clickHandler={(e) => {}}
    />);
}
package:
  name: department-of-veteran-affairs/jean-pants
  version: 0.1.0
assetPath: /design-system/
isProduction: true
componentSourcePath: ./DropDownPanel.jsx
id: default
buttonText: Helpdesk
cssClass: va-dropdown
isOpen: true
contents: >-
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce ullamcorper at
  eros eu suscipit. Ut imperdiet libero et luctus pretium.
  • Content:
    import PropTypes from 'prop-types';
    import React from 'react';
    import classNames from 'classnames';
    import root from 'window-or-global';
    
    class DropDownPanel extends React.Component {
    
      constructor(props) {
        super(props);
        this.toggleDropDown = this.toggleDropDown.bind(this);
        this.handleDocumentClick = this.handleDocumentClick.bind(this);
      }
    
      componentDidMount() {
        this.props.container.addEventListener('click', this.handleDocumentClick, false);
      }
    
      componentWillUnmount() {
        this.props.container.removeEventListener('click', this.handleDocumentClick, false);
      }
    
      handleDocumentClick(event) {
        // If this dropdown is open, and it's not an element within this dropdown being clicked,
        // then the user clicked elsewhere and we should invoke the click handler to toggle this
        // dropdown to closed.
        if (this.props.isOpen && !this.dropdownDiv.contains(event.target)) {
          this.toggleDropDown();
        }
      }
    
      toggleDropDown() {
        this.props.clickHandler();
      }
    
      render() {
        const buttonClasses = classNames(
          this.props.cssClass,
          { 'va-btn-withicon': this.props.icon },
          'va-dropdown-trigger'
        );
    
        return (
          <div className="va-dropdown" ref={div => { this.dropdownDiv = div; }}>
            <button className={buttonClasses}
              aria-controls={this.props.id}
              aria-expanded={this.props.isOpen}
              disabled={this.props.disabled}
              onClick={this.toggleDropDown}>
              <span>
                {this.props.icon}
                {this.props.buttonText}
              </span>
            </button>
            <div className="va-dropdown-panel" id={this.props.id} hidden={!this.props.isOpen}>
              {this.props.contents}
            </div>
          </div>
        );
      }
    }
    
    DropDownPanel.propTypes = {
      buttonText: PropTypes.string.isRequired,
      clickHandler: PropTypes.func.isRequired,
      cssClass: PropTypes.string,
      contents: PropTypes.node.isRequired,
      icon: PropTypes.node, /* Should be SVG markup */
      id: PropTypes.string,
      isOpen: PropTypes.bool.isRequired,
      disabled: PropTypes.bool,
      // 'container' is the parent DOM element that will close the dropdown when clicked,
      // assuming the child element is not contained by the dropdown's element.
      // This is a DOM element, not a React element, because the dropdown may need to respond
      // to events occurring outside of the React context.
      container: PropTypes.oneOfType([
        PropTypes.instanceOf(root.HTMLDocument),
        PropTypes.instanceOf(root.HTMLElement)
      ])
    };
    
    DropDownPanel.defaultProps = {
      container: root.document,
      disabled: false
    };
    
    export default DropDownPanel;
    
  • URL: /components/raw/dropdownpanel/DropDownPanel.jsx
  • Filesystem Path: src/components/navigation/DropDownPanel/DropDownPanel.jsx
  • Size: 2.6 KB
  • Content:
    import React from 'react';
    import ReactDOM from 'react-dom';
    import { expect } from 'chai';
    import sinon from 'sinon';
    
    import DropDown from './DropDownPanel.jsx';
    
    describe('<DropDownPanel>', () => {
      let clickHandler;
      let container;
      let props;
    
      beforeEach(() => {
        clickHandler = sinon.stub();
        container = window.document.createElement('div');
    
        container.addEventListener = sinon.spy(container.addEventListener.bind(container));
        container.removeEventListener = sinon.spy(container.removeEventListener.bind(container));
    
        props = {
          buttonText: 'Button text',
          clickHandler,
          container,
          contents: (<h1>Hi</h1>),
          cssClass: 'testClass',
          isOpen: true,
          icon: (<svg><rect x="50" y="50" width="50" height="50"/></svg>),
          id: 'testId'
        };
    
        ReactDOM.render(<DropDown {...props}/>, container);
      });
    
      it('should render', () => {
      //  const dropdownDOM = ReactDOM.findDOMNode(container);
      //  expect(dropdownDOM).to.not.be.undefined;
      });
    
      it('should register event listeners on the parent element', () => {
        expect(container.addEventListener.called).to.be.true;
      });
    
      it('should call clickHandler when the parent element\'s click event occurs', () => {
        expect(clickHandler.called).to.be.false;
        container.dispatchEvent(new window.MouseEvent('click'));
        expect(clickHandler.called).to.be.true;
      });
    
      it('should unregister event listeners on the parent element', () => {
        ReactDOM.unmountComponentAtNode(container);
        expect(container.removeEventListener.called).to.be.true;
      });
    
    });
    
  • URL: /components/raw/dropdownpanel/DropDownPanel.unit.spec.jsx
  • Filesystem Path: src/components/navigation/DropDownPanel/DropDownPanel.unit.spec.jsx
  • Size: 1.6 KB
  • Handle: @dropdownpanel
  • Preview:
  • Filesystem Path: src/components/navigation/DropDownPanel/DropDownPanel.njk