From f3d478ba6c7adc645993e2d1bb5c65e01930ba5c Mon Sep 17 00:00:00 2001 From: Daniel Walmsley Date: Fri, 13 May 2016 10:47:12 -0700 Subject: [PATCH] Update Notice component from wp-calypso --- client/components/notice/index.jsx | 198 ++++++++++++++++---- client/components/notice/style.scss | 275 ++++++++++++++-------------- package.json | 1 + 3 files changed, 304 insertions(+), 170 deletions(-) diff --git a/client/components/notice/index.jsx b/client/components/notice/index.jsx index 21af4fd..caeb52a 100644 --- a/client/components/notice/index.jsx +++ b/client/components/notice/index.jsx @@ -1,51 +1,61 @@ /** * External dependencies */ -var React = require( 'react/addons' ), - joinClasses = require( 'react/lib/joinClasses' ), - noop = require( 'lodash/noop' ); +import React, { PropTypes } from 'react'; +import classnames from 'classnames'; +import noop from 'lodash/noop'; +import ScreenReaderText from '../screen-reader-text'; +import i18n from 'lib/mixins/i18n'; + +require( './style.scss' ); /** * Internal dependencies */ -var Button = require( '../button' ), - Gridicon = require( '../gridicon' ), - ScreenReaderText = require( '../screen-reader-text' ); - -require( './style.scss' ); +import Gridicon from '../gridicon'; -module.exports = React.createClass( { +export default React.createClass( { + mixins: [ i18n.mixin ], displayName: 'SimpleNotice', + dismissTimeout: null, - getDefaultProps: function() { + getDefaultProps() { return { - status: 'is-info', + duration: 0, + status: null, showDismiss: true, className: '', - onClick: noop + onDismissClick: noop }; }, propTypes: { // we should validate the allowed statuses - status: React.PropTypes.string, - showDismiss: React.PropTypes.bool, + status: PropTypes.string, + showDismiss: PropTypes.bool, + isCompact: PropTypes.bool, duration: React.PropTypes.number, - isCompact: React.PropTypes.bool, - text: React.PropTypes.oneOfType( [ - React.PropTypes.string, - React.PropTypes.object + text: PropTypes.oneOfType( [ + PropTypes.oneOfType( [ PropTypes.string, PropTypes.node ] ), + PropTypes.arrayOf( PropTypes.oneOfType( [ PropTypes.string, PropTypes.node ] ) ) ] ), - className: React.PropTypes.string + icon: PropTypes.string, + className: PropTypes.string }, - componentDidMount: function() { + componentDidMount() { if ( this.props.duration > 0 ) { - setTimeout( this.props.onClick, this.props.duration ); + this.dismissTimeout = setTimeout( this.props.onDismissClick, this.props.duration ); + } + }, + + componentWillUnmount() { + if ( this.dismissTimeout ) { + clearTimeout( this.dismissTimeout ); } }, - renderChildren: function() { + renderChildren() { let content; if ( typeof this.props.children === 'string' ) { @@ -62,35 +72,159 @@ module.exports = React.createClass( { return content; }, - render: function() { - var noticeClass, dismiss; + getIcon() { + let icon; + + switch ( this.props.status ) { + case 'is-info': + icon = 'info'; + break; + case 'is-success': + icon = 'checkmark'; + break; + case 'is-error': + icon = 'notice'; + break; + case 'is-warning': + icon = 'notice'; + break; + default: + icon = 'info'; + break; + } + + return icon; + }, + + render() { + let dismiss; // The class determines the nature of a notice // and its status. - noticeClass = joinClasses( 'notice', this.props.status ); + let noticeClass = classnames( 'notice', this.props.status ); if ( this.props.isCompact ) { - noticeClass = joinClasses( noticeClass, 'is-compact' ); + noticeClass = classnames( noticeClass, 'is-compact' ); } // By default, a dismiss button is rendered to // allow the user to hide the notice if ( this.props.showDismiss ) { - noticeClass = joinClasses( noticeClass, 'is-dismissable' ); + noticeClass = classnames( noticeClass, 'is-dismissable' ); dismiss = ( - + ); } return ( -
- { this.renderChildren() } +
+ +
+ { this.renderChildren() } +
{ dismiss }
); } - } ); + + +// /** +// * External dependencies +// */ +// var React = require( 'react/addons' ), +// joinClasses = require( 'react/lib/joinClasses' ), +// noop = require( 'lodash/noop' ); + +// /** +// * Internal dependencies +// */ +// var Button = require( '../button' ), +// Gridicon = require( '../gridicon' ), +// ScreenReaderText = require( '../screen-reader-text' ); + +// require( './style.scss' ); + +// module.exports = React.createClass( { +// displayName: 'SimpleNotice', + +// getDefaultProps: function() { +// return { +// status: 'is-info', +// showDismiss: true, +// className: '', +// onClick: noop +// }; +// }, + +// propTypes: { +// // we should validate the allowed statuses +// status: React.PropTypes.string, +// showDismiss: React.PropTypes.bool, +// duration: React.PropTypes.number, +// isCompact: React.PropTypes.bool, +// text: React.PropTypes.oneOfType( [ +// React.PropTypes.string, +// React.PropTypes.object +// ] ), +// className: React.PropTypes.string +// }, + +// componentDidMount: function() { +// if ( this.props.duration > 0 ) { +// setTimeout( this.props.onClick, this.props.duration ); +// } +// }, + +// renderChildren: function() { +// let content; + +// if ( typeof this.props.children === 'string' ) { +// return { this.props.children }; +// } + +// if ( this.props.text ) { +// content = [ this.props.children ]; +// content.unshift( { this.props.text } ); +// } else { +// content = { this.props.children }; +// } + +// return content; +// }, + +// render: function() { +// var noticeClass, dismiss; + +// // The class determines the nature of a notice +// // and its status. +// noticeClass = joinClasses( 'notice', this.props.status ); + +// if ( this.props.isCompact ) { +// noticeClass = joinClasses( noticeClass, 'is-compact' ); +// } + +// // By default, a dismiss button is rendered to +// // allow the user to hide the notice +// if ( this.props.showDismiss ) { +// noticeClass = joinClasses( noticeClass, 'is-dismissable' ); +// dismiss = ( +// +// ); +// } + +// return ( +//
+// { this.renderChildren() } +// { dismiss } +//
+// ); +// } + +// } ); diff --git a/client/components/notice/style.scss b/client/components/notice/style.scss index 7da33fd..74fd403 100644 --- a/client/components/notice/style.scss +++ b/client/components/notice/style.scss @@ -3,121 +3,88 @@ @import '../../scss/extends'; .notice { - flex: 1 100%; display: flex; - flex-wrap: wrap; position: relative; margin-bottom: 24px; border-radius: 1px; - background: $gray-light; + background: lighten( $gray, 30 ); box-sizing: border-box; font-size: 14px; - line-height: 1.4285; animation: appear .3s ease-in-out; - .notice__text { - flex-grow: 1; - flex-basis: 100px; - - padding: 11px 24px; - padding-right: 0; - - @include breakpoint( ">660px" ) { - padding: 13px 48px; - } - } - @include breakpoint( ">660px" ) { font-size: inherit; - - &::before { - @extend %noticon; - content: '\f456'; - position: absolute; - top: 26px; - left: 20px; - margin: -12px 0px 0 -8px; - font-size: 24px; - line-height: 1; - } - } - - .notice__dismiss:focus { - box-shadow: 0 0 4px darken( $gray-light, 10 ); } // Success! &.is-success { background: $alert-green; - - .notice__dismiss:focus { - box-shadow: 0 0 4px darken( $alert-green, 10 ); - } - - @include breakpoint( ">660px" ) { - &:before { - content: '\f418'; - } - } } // Warning &.is-warning { background: $alert-yellow; - - .notice__dismiss:focus { - box-shadow: 0 0 4px darken( $alert-yellow, 10 ); - } - - &:before { - } } // Error! OHNO! &.is-error { background: $alert-red; - - .notice__dismiss:focus { - box-shadow: 0 0 4px darken( $alert-red, 10 ); - } - - &:before { - } } - // Information + // General notice &.is-info { background: $blue-wordpress; + } + + &.is-success, + &.is-error, + &.is-warning, + &.is-info { + color: $white; - .notice__dismiss:focus { - box-shadow: 0 0 4px darken( $blue-wordpress, 10 ); + .notice__text a { + color: $white; } - @include breakpoint( ">660px" ) { - &:before { - content: '\f455'; - } + .notice__dismiss { + color: $white; } } } -// General styles for html elements -// rendered inside a notice -.notice { +.notice__icon { + flex-shrink: 0; + padding: 13px 0 13px 16px; - a, - button.is-link { - display: inline; - margin-left: 8px; - text-align: left; - line-height: 1.4285; - font-weight: 600; - text-decoration: underline; + @include breakpoint( "<660px" ) { + display: none; + } +} + +.notice__content { + display: flex; + flex-grow: 1; + + @include breakpoint( "<480px" ) { + flex-direction: column; + } +} + +.notice__text { + font-size: 15px; + padding: 11px 24px; + + & > span, + & > div { + max-width: 680px; + } + + @include breakpoint( ">660px" ) { + padding: 13px; + } - // @media not all, only screen and (min-resolution: 2dppx), only screen and (-webkit-min-device-pixel-ratio: 2) { - // background-image: linear-gradient(to bottom, rgba(0,0,0,0) 75%, #fff 75%); - // background-repeat: repeat-x; - // } + a { + text-decoration: underline; } ul { @@ -138,31 +105,6 @@ margin-top: 0; } } - - &.is-success, // TODO fix this in pre-oss to be less bad - &.is-error, - &.is-warning, - &.is-info { - color: $white; - - span { - color: inherit; - } - - a, - button.is-link { - color: rgba( $white, 0.85 ); - - &:hover, - &:focus { - color: $white; - } - } - - .notice__dismiss { - color: $white; - } - } } .notice__button { @@ -173,14 +115,11 @@ // "X" for dismissing a notice .notice__dismiss { display: flex; - padding: 9px 16px; + flex-shrink: 0; + padding: 11px 16px; cursor: pointer; color: $gray; - background: transparent; - border: none; - border-radius: 0; - @include breakpoint( ">660px" ) { padding: 13px 16px; } @@ -201,51 +140,111 @@ } } -// Compact notices -.notice.is-compact { - margin-bottom: 8px; - font-size: 14px; - - .notice__text { - padding: 11px 0px 11px 16px; - } - - &::before { - display: none; - } - - .notice__dismiss { - padding: 9px 16px; - } - - a.notice__arrow-link .gridicon { - width: 18px; - height: 18px; - } -} - -// ArrowLink sub-component // specificity for general `a` elements within notice is too great -.notice a.notice__arrow-link { - background: rgba( 0, 0, 0, 0.2 ); - box-sizing: border-box; - color: $white; - cursor: pointer; +a.notice__action { display: flex; align-items: center; + flex-shrink: 0; + box-sizing: border-box; + cursor: pointer; + font-size: 15px; font-weight: 400; - line-height: 1.2; margin-left: auto; // forces the element to the right; - padding: 13px 10px 13px 16px; + padding: 13px 16px; text-decoration: none; white-space: nowrap; + .is-success &, + .is-error &, + .is-warning &, + .is-info & { + color: $white; + } + + .is-success & { background: darken( $alert-green, 15 ); } + .is-error & { background: darken( $alert-red, 15 ); } + .is-warning & { background: darken( $alert-yellow, 15 ); } + .is-info & { background: darken( $blue-wordpress, 15 ); } + .gridicon { margin-left: 8px; + opacity: 0.7; } &:hover, &:focus { background: rgba( 255, 255, 255, 0.2 ); } + + @include breakpoint( "<480px" ) { + margin: 0; + justify-content: flex-end; + } +} + +// Compact notices +.notice.is-compact { + border-radius: 2px; + display: inline-flex; + flex-wrap: nowrap; + min-height: 20px; + margin: 0; + padding: 0; + text-decoration: none; + text-transform: none; + vertical-align: middle; + + &.is-success, + &.is-error, + &.is-warning, + &.is-info { + color: $white; + } + + .notice__text { + font-size: 12px; + padding: 6px 8px; + line-height: 1; + } + + .notice__icon { + align-self: center; + flex-shrink: 0; + margin: 0 0 0 8px; + padding: 0; + width: 18px; + height: 18px; + vertical-align: middle; + } + + .notice__dismiss { + display: none; + } + + a.notice__action { + background: transparent; + display: inline-block; + font-size: 11px; + font-weight: 600; + align-self: center; + margin-left: 16px; + padding: 0 8px; + text-decoration: underline; + text-transform: uppercase; + + &:hover, + &:active, + &:focus { + background: transparent; + text-decoration: none; + } + + .gridicon { + margin-left: 8px; + width: 14px; + height: 14px; + vertical-align: sub; + opacity: 1; + } + } } diff --git a/package.json b/package.json index 9352029..ea5bde2 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "babel-core": "5.8.12", "babel-eslint": "^4.1.1", "babel-loader": "^5.3.2", + "babel-runtime": "^5.8.12", "codemirror": "^5.6.0", "css-loader": "^0.16.0", "eslint": "^1.9.0",