Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
Size: Mime:
import React, { Component } from 'react';
import classnames from 'classnames';
import PropTypes from 'prop-types';
import IconButton from '../../controls/Button/IconButton';
import CloseIcon from '../../visuals/Icon/svg/ic_close.svg';

// unique id for a11y labels
let uniqueNagIdCounter = 0;
const nextUniqueNagId = () => ++uniqueNagIdCounter; // eslint-disable-line no-plusplus

class Nag extends Component {
  static propTypes = {
    /** A nag always needs a close label (as an `alertdialog` it always has a visually hidden close button) */
    closeLabel: PropTypes.string.isRequired,
    /** Content of notification */
    children: PropTypes.node.isRequired,
    /** As a function, it will be called with { dismiss: PropTypes.func } which triggers the fadeout  */
    actions: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
    /** Nag type, defaults to success */
    type: PropTypes.oneOf(['error', 'success', 'notice', 'neutral']),
    /** For visually "docking" the notifications to a sibing container */
    docked: PropTypes.oneOf(['top', 'bottom']),
    /** Controls wether the Nag is dismissable or autocloses: when provided with a `onClose` function the nag becomes dismissable and does not autoclose. */
    onClose: PropTypes.func,
    /** If true, the close button is only visible for screen readers, and after `autoCloseTimeout` ms the Nag automatically closes and calls `onAutoClose` */
    autoClose: PropTypes.bool,
    /** After this timeout, when there is no `onClose` provided, the nag will autoclose. */
    autoCloseTimeout: PropTypes.number,
    /** Callback triggered after autoclosing */
    onAutoClose: PropTypes.func,
  };

  static defaultProps = {
    type: 'success',
    actions: null,
    onClose: null,
    autoClose: false,
    onAutoClose: null,
    autoCloseTimeout: 5000,
    docked: null,
  };

  // nag phases: a nag always cycles forward through 'entering', 'closing' and 'closed' for visual candy
  static phases = {
    ENTERING: 'entering',
    CLOSING: 'closing',
    CLOSED: 'closed',
  };

  state = { phase: Nag.phases.ENTERING };

  componentDidMount() {
    const { autoClose, autoCloseTimeout } = this.props;
    if (autoClose) {
      this.closeTimeoutId = setTimeout(this.close, autoCloseTimeout);
    }
  }

  componentWillUnmount() {
    clearTimeout(this.closeTimeoutId);
    clearTimeout(this.closingTimeoutId);
  }

  close = () => {
    const { onClose, autoClose, onAutoClose } = this.props;
    this.setState({ phase: Nag.phases.CLOSING }, () => {
      this.closingTimeoutId = setTimeout(() => {
        this.setState({
          phase: Nag.phases.CLOSED,
        });
        if (typeof onClose === 'function') {
          onClose();
        }
        if (autoClose && typeof onAutoClose === 'function') {
          onAutoClose();
        }
      }, 300);
    });
  };

  render() {
    // some props are not used in render but we pluck them to keep able to pass down arbitrary
    // attributes to root level DOM element and avoid warnings for unrecognized prop on dom element
    const {
      closeLabel,
      children,
      actions,
      type,
      docked,
      autoClose,
      // eslint-disable-next-line no-unused-vars
      onClose,
      // eslint-disable-next-line no-unused-vars
      autoCloseTimeout,
      // eslint-disable-next-line no-unused-vars
      onAutoClose,
      ...props
    } = this.props;
    const { phase } = this.state;
    const uniqueId = nextUniqueNagId();

    return phase === Nag.phases.CLOSED ? null : (
      <div
        role="alertdialog"
        aria-labelledby={`Nag-uniqueLabel${uniqueId}`}
        className={classnames('Nag', `Nag--${type}`, `Nag--${phase}`, { [`Nag--dock${docked}`]: docked })}
        {...props}
      >
        <div className={classnames('Nag-closeButton', { 'u-srOnly': autoClose })}>
          <IconButton icon={CloseIcon} semantic={closeLabel} variant="linkWhite" onClick={this.close} />
        </div>

        <div className="Nag-content" id={`Nag-uniqueLabel${uniqueId}`}>
          {children}
        </div>

        {actions && (
          <div className="Nag-actions">
            {typeof actions === 'function' ? actions({ dismiss: this.close }) : actions}
          </div>
        )}
      </div>
    );
  }
}

export default Nag;