Snackbar

<section>
    <div class="row">
        <div class="col _span-12">
            <form action="#" class="Form js-snackbar-open">
                <label>
					<span>Message</span>
					<input
							name="message"
							type="text"
							placeholder="Message"
							value="What a tasty snack."
							required
					>
				</label>

                <p><button class="button">Grab a snack</button></p>
            </form>
        </div>
    </div>
</section>

<!--<div class="js-snackbar"></div>-->
<section>
	<div class="row">
		<div class="col _span-12">
			<form action="#" class="Form js-snackbar-open">
				<label>
					<span>Message</span>
					<input
							name="message"
							type="text"
							placeholder="Message"
							value="What a tasty snack."
							required
					>
				</label>

				<p><button class="button">Grab a snack</button></p>
			</form>
		</div>
	</div>
</section>

<!--<div class="js-snackbar"></div>-->
/* No context defined for this component. */
  • Content:
    import PropTypes from 'prop-types';
    import React from 'react';
    
    /**
     * @typedef {Object} Message - A message for the Snackbar to display.
     * @property {string} text - The message inner HTML content.
     * @property {string} [action] - The text for the message action button.
     * @property {string} [callback] - The function to run when the action button is pressed.
     */
    
    /**
     * A message that is displayed in a Snackbar.
     */
    class SnackMessage extends React.Component {
        static propTypes = {
            text: PropTypes.string.isRequired,
            action: PropTypes.string,
            callback: PropTypes.func
        };
    
        /**
         * @type Message
         */
        static defaultProps = {
            text: '',
            action: '',
            callback: () => true
        };
    
        render() {
            const action = this.props.action ? (
                <button
                    className="Snackbar-action"
                    onClick={this.props.callback}
                >
                    {this.props.action}
                </button>
            ) : '';
    
            /*eslint-disable*/
            return (
                <div className="Snackbar">
                    <p dangerouslySetInnerHTML={{__html: this.props.text}} />
                    {action}
                </div>
            );
            /*eslint-enable*/
        }
    }
    
    export default SnackMessage;
    
  • URL: /components/raw/snackbar/SnackMessage.jsx
  • Filesystem Path: components/organisms/Snackbar/SnackMessage.jsx
  • Size: 1.3 KB
  • Content:
    import PropTypes from 'prop-types';
    import React from 'react';
    import { CSSTransitionGroup } from 'react-transition-group';
    
    import SnackMessage from './SnackMessage';
    
    /**
     * Opens a small window to notify a user of an event.
     */
    class Snackbar extends React.Component {
        static propTypes = {
            message: PropTypes.object,
            ttl: PropTypes.number
        };
    
        /**
         * @type {{message: Message, ttl: number}}
         */
        static defaultProps = {
            message: {},
            ttl: 8000
        };
    
        /**
         * Creates a Snackbar with a given message, clearing any previous ones.
         * @param {Object} props
         * @param {Message} props.message - A message to be displayed.
         * @param {number} props.ttl - The time until a displayed message disappears after no interaction.
         */
        constructor(props) {
            super(props);
            const message = this.props.message;
            if (message) {
                message.id = new Date().getTime();
                this.state = {
                    messages: [message]
                };
                this.timedRemove(message);
            }
        }
    
        componentWillReceiveProps(nextProps) {
            if (nextProps.message) {
                nextProps.message.id = new Date().getTime();
                this.setState({
                    messages: [nextProps.message]
                });
            }
        }
    
        /**
         * Removes an existing message from the Snackbar.
         * @param {Message} message
         */
        removeMessage(message) {
            this.setState({
                messages: this.state.messages
                    .filter((m) => m.id != message.id)
            });
        }
    
        /**
         * Removes an existing message after the set TTL.
         * @param {Message} message
         */
        timedRemove(message) {
            setTimeout(this.removeMessage.bind(this, message), this.props.ttl);
        }
    
        render() {
            const message = this.state.messages[0];
            let callback;
    
            if (message) {
                this.timedRemove(message);
                callback = message.action ? () => {
                    this.removeMessage(message);
                    if (message.callback) message.callback();
                } : undefined;
            }
    
            return (
                <div className="Snackbar-container">
                    <div className="Snackbar-group">
                        <CSSTransitionGroup
                            transitionName={{enter: 'enter', leave: 'leave', appear: 'enter'}}
                            transitionAppear={true}
                            transitionAppearTimeout={200}
                            transitionEnterTimeout={200}
                            transitionLeaveTimeout={200}
                        >
                            {message &&
                                <SnackMessage
                                    key={message.id}
                                    text={message.text}
                                    action={message.action}
                                    callback={callback}
                                />
                            }
                        </CSSTransitionGroup>
                    </div>
                </div>
            );
        }
    }
    
    export default Snackbar;
    
  • URL: /components/raw/snackbar/Snackbar.jsx
  • Filesystem Path: components/organisms/Snackbar/Snackbar.jsx
  • Size: 3.1 KB
  • Content:
    // Snackbar
    //
    // OM NOM NOM.
    .Snackbar {
        @include Elevation("Snackbar");
        position: relative;
        display: flex;
        max-height: 200px;
        min-width: 240px;
        padding: 1rem 1.5rem;
        margin-top: .75rem;
        justify-content: space-between;
        align-items: flex-end;
        color: get-color(neutral, 0);
        background-color: get-color(neutral, 1000);
        opacity: 1;
        border-radius: $Border-radius--500;
        transition: transform $transition-time-default $transition-in-default;
        transform: translate3d(0, 0, 0);
        pointer-events: auto;
        h4 {
            color: get-color(neutral, 0);
        }
        p {
            @include font-size-small;
            margin-top: 0;
        }
        &-action {
            @include spaced-out;
            @include font-size-small;
            display: block;
            padding: 0;
            margin-left: 20px;
            color: theme-color(link);
            background: none;
            border: 0;
        }
        &.enter,
        &.leave {
            max-height: 0;
            opacity: 0;
            transform: translate3d(0, 20px, 0);
        }
    }
    .Snackbar-group {
        display: inline-flex;
        max-width: 780px;
        flex-direction: column;
    }
    .Snackbar-container {
        @include ZIndex("Snackbar");
        position: fixed;
        right: 0;
        bottom: 0;
        left: 0;
        text-align: center;
        pointer-events: none;
    }
    @media #{$mobile-media} {
        .Snackbar-group,
        .Snackbar {
            width: 100%;
            border-radius: 0;
        }
    }
    
  • URL: /components/raw/snackbar/Snackbar.scss
  • Filesystem Path: components/organisms/Snackbar/Snackbar.scss
  • Size: 1.4 KB

There are no notes for this item.