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';

// Unique id for a11y labels
let uniqueNotificationIdCounter = 0;
const nextUniqueNotificationId = () => ++uniqueNotificationIdCounter; // eslint-disable-line no-plusplus

class Notification extends Component {
  static propTypes = {
    /** Content of notification */
    children: PropTypes.node.isRequired,
    /** Add custom actions to the Notification */
    actions: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
    /** Notification 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']),
    /** If true, the Notification will auto close after the `autoCloseTimeout` has expired, then calls the `onAutoClose` callback, if supplied */
    autoClose: PropTypes.bool,
    /** After this timeout, when `autoClose` is true, the notification will autoclose. */
    autoCloseTimeout: PropTypes.number,
    /** Callback triggered after autoclosing */
    onAutoClose: PropTypes.func,
  };

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

  // Notification phases: a Notification cycles through 'entering' > 'closing' > 'closed' for visual candy
  static phases = {
    ENTERING: 'entering',
    CLOSING: 'closing',
    CLOSED: 'closed',
  };

  state = { phase: Notification.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 { autoClose, onAutoClose } = this.props;
    this.setState({ phase: Notification.phases.CLOSING }, () => {
      this.closingTimeoutId = setTimeout(() => {
        this.setState({
          phase: Notification.phases.CLOSED,
        });
        if (autoClose && typeof onAutoClose === 'function') {
          onAutoClose();
        }
      }, 300);
    });
  };

  render() {
    // Some props are not used in render but we pluck them to be able to pass them down as arbitrary
    // attributes to the root level DOM element and avoid warnings for unrecognized prop on DOM element
    const {
      children,
      actions,
      type,
      docked,
      // eslint-disable-next-line no-unused-vars
      autoClose,
      // 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 = nextUniqueNotificationId();

    return phase === Notification.phases.CLOSED ? null : (
      <div
        role="alert"
        aria-labelledby={`Notification-uniqueLabel${uniqueId}`}
        className={classnames('Notification', `Notification--${type}`, `Notification--${phase}`, {
          [`Notification--dock${docked}`]: docked,
        })}
        {...props}
      >
        <div className="Notification-content" id={`Notification-uniqueLabel${uniqueId}`}>
          {children}
        </div>

        {actions ? (
          <div className="Notification-actions">{typeof actions === 'function' ? actions() : actions}</div>
        ) : null}
      </div>
    );
  }
}

export default Notification;