This repository was archived by the owner on Oct 4, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 51
Add a dismissable Alert component with 4 different styles: info, warning, error & success. #332
Open
Dieterrr
wants to merge
20
commits into
develop
Choose a base branch
from
add-alert-component
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 6 commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
b5592bc
Added Alert component and required icons
4cdadce
Added Alert component to components, added example to App
b84c7b8
Fixed eslint errors
aad4bcb
CSS and docs improvements.
afercia b2cef0b
Commit modified yarn lock file.
afercia 2d874e1
Change the cookie value.
afercia f1c47fe
Replaced react-intl with wordpress-i18n, changed cookie value for hide
305dcb9
added yarn.lock
60ee505
merged origin
eb06ca5
Added 4 snapshot tests
f436616
CS update
103f071
updated snapshot tests for search-metadata
92761fc
updated warnings
9248de8
fix color for links
JoseeWouters f2e0afa
Merge branch 'develop' into add-alert-component
37bd9d3
merged develop, updated tests
bfcc585
reverted yarn.lock
d2083a2
Merge branch 'develop' into add-alert-component
a0001e5
add new yarn.lock file
c398929
Revert "reverted yarn.lock"
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,273 @@ | ||
| /* External dependencies */ | ||
| import React from "react"; | ||
| import styled from "styled-components"; | ||
| import PropTypes from "prop-types"; | ||
| import Cookies from "js-cookie"; | ||
| import { defineMessages, injectIntl, intlShape } from "react-intl"; | ||
|
|
||
| /* Yoast dependencies */ | ||
| import { colors } from "@yoast/style-guide"; | ||
|
|
||
| /** | ||
| * Returns an error icon SVG data URI. | ||
| * | ||
| * @param {string} color The desired color for the SVG. | ||
| * | ||
| * @returns {string} The SVG image data URI. | ||
| */ | ||
| const errorIcon = ( color ) => | ||
| "data:image/svg+xml;charset=utf8," + encodeURIComponent( | ||
| '<svg width="1792" height="1792" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">' + | ||
| // eslint-disable-next-line | ||
| '<path fill="' + color + '" d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm121.6 313.1c4.7 4.7 4.7 12.3 0 17L338 377.6c-4.7 4.7-12.3 4.7-17 0L256 312l-65.1 65.6c-4.7 4.7-12.3 4.7-17 0L134.4 338c-4.7-4.7-4.7-12.3 0-17l65.6-65-65.6-65.1c-4.7-4.7-4.7-12.3 0-17l39.6-39.6c4.7-4.7 12.3-4.7 17 0l65 65.7 65.1-65.6c4.7-4.7 12.3-4.7 17 0l39.6 39.6c4.7 4.7 4.7 12.3 0 17L312 256l65.6 65.1z" />' + | ||
| "</svg>" | ||
| ); | ||
|
|
||
| /** | ||
| * Returns an info icon SVG data URI. | ||
| * | ||
| * @param {string} color The desired color for the SVG. | ||
| * | ||
| * @returns {string} The SVG image data URI. | ||
| */ | ||
| export const infoIcon = ( color ) => | ||
| "data:image/svg+xml;charset=utf8," + encodeURIComponent( | ||
| '<svg width="1792" height="1792" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">' + | ||
| // eslint-disable-next-line | ||
| '<path fill="' + color + '" d="M256 8C119.043 8 8 119.083 8 256c0 136.997 111.043 248 248 248s248-111.003 248-248C504 119.083 392.957 8 256 8zm0 110c23.196 0 42 18.804 42 42s-18.804 42-42 42-42-18.804-42-42 18.804-42 42-42zm56 254c0 6.627-5.373 12-12 12h-88c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h12v-64h-12c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h64c6.627 0 12 5.373 12 12v100h12c6.627 0 12 5.373 12 12v24z" />' + | ||
| "</svg>" | ||
| ); | ||
|
|
||
| /** | ||
| * Returns a warning icon SVG data URI. | ||
| * | ||
| * @param {string} color The desired color for the SVG. | ||
| * | ||
| * @returns {string} The SVG image data URI. | ||
| */ | ||
| export const warningIcon = ( color ) => | ||
| "data:image/svg+xml;charset=utf8," + encodeURIComponent( | ||
| '<svg width="1792" height="1792" viewBox="0 0 576 512" xmlns="http://www.w3.org/2000/svg">' + | ||
| // eslint-disable-next-line | ||
| '<path fill="' + color + '" d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z" />' + "</svg>" | ||
| ); | ||
|
|
||
| /** | ||
| * Returns a success icon SVG data URI. | ||
| * | ||
| * @param {string} color The desired color for the SVG. | ||
| * | ||
| * @returns {string} The SVG image data URI. | ||
| */ | ||
| export const successIcon = ( color ) => | ||
| "data:image/svg+xml;charset=utf8," + encodeURIComponent( | ||
| '<svg width="1792" height="1792" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">' + | ||
| // eslint-disable-next-line | ||
| '<path fill="' + color + '" d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z" />' + | ||
| "</svg>" | ||
| ); | ||
|
|
||
| /** | ||
| * Returns a close icon SVG data URI. | ||
| * | ||
| * @param {string} color The desired color for the SVG. | ||
| * | ||
| * @returns {string} The SVG image data URI. | ||
| */ | ||
| export const closeIcon = ( color ) => | ||
| "data:image/svg+xml;charset=utf8," + encodeURIComponent( | ||
| '<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">' + | ||
| // eslint-disable-next-line | ||
| '<path fill="' + color + '" d="M1490 1322q0 40-28 68l-136 136q-28 28-68 28t-68-28l-294-294-294 294q-28 28-68 28t-68-28l-136-136q-28-28-28-68t28-68l294-294-294-294q-28-28-28-68t28-68l136-136q28-28 68-28t68 28l294 294 294-294q28-28 68-28t68 28l136 136q28 28 28 68t-28 68l-294 294 294 294q28 28 28 68z" />' + "</svg>" | ||
| ); | ||
|
|
||
| const messages = defineMessages( { | ||
| close: { | ||
| id: "alert.close", | ||
| defaultMessage: "close", | ||
| }, | ||
| } ); | ||
|
|
||
| const AlertBody = styled.div` | ||
| display: flex; | ||
| align-items: center; | ||
| font-size: 14px; | ||
| border: 1px solid rgba(0, 0, 0, 0.2); | ||
| padding: 16px; | ||
| color: ${ props => props.alertColor }; | ||
| background: ${ props => props.alertBackground }; | ||
| margin-bottom: 20px; | ||
|
|
||
| a { | ||
| color: ${ colors.$palette_alert_blue_link }; | ||
|
|
||
| &:hover, | ||
| &:focus { | ||
| color: ${ colors.$palette_alert_blue_link }; | ||
| } | ||
| } | ||
| `; | ||
|
|
||
| const AlertIcon = styled.span` | ||
| align-self: flex-start; | ||
| background-position: 50%; | ||
| background-repeat: no-repeat; | ||
| background-size: 1rem; | ||
| background-image: url( ${ props => props.icon } ); | ||
| height: 1rem; | ||
| min-width: 1rem; | ||
| margin: 0.125rem 1em 0 0.125rem; | ||
| `; | ||
|
|
||
| const AlertMessage = styled.div` | ||
| flex: 1 1 auto; | ||
|
|
||
| & p:first-child { | ||
| margin-top: 0; | ||
| } | ||
|
|
||
| & p:last-child { | ||
| margin-bottom: 0; | ||
| } | ||
| `; | ||
|
|
||
| const StyledCloseButtonTopRight = styled.button` | ||
| align-self: flex-start; | ||
| height: 1.25rem; | ||
| min-width: 1.25rem; | ||
| margin: 0 0 0 1em; | ||
| padding: 0; | ||
| border: 0; | ||
| cursor: pointer; | ||
| background: transparent url( ${ props => props.iconSource } ) no-repeat center; | ||
| background-size: ${ props => props.iconSize }; | ||
|
|
||
| &:hover, | ||
| &:focus { | ||
| opacity: 1; | ||
| } | ||
| `; | ||
|
|
||
| /** | ||
| * Returns the rendered Alert component. | ||
| * | ||
| * @param {Object} props The props to use. | ||
| * | ||
| * @returns {ReactElement} The rendered Alert component. | ||
| */ | ||
| class Alert extends React.Component { | ||
| /** | ||
| * Initializes the class with the specified props. | ||
| * | ||
| * @param {Object} props The props to be passed to the class that was extended from. | ||
| * | ||
| * @returns {void} | ||
| */ | ||
| constructor( props ) { | ||
| super( props ); | ||
| this.state = { | ||
| hideAlert: false, | ||
| }; | ||
| this.onCrossClick = this.onCrossClick.bind( this ); | ||
| this.options = this.getTypeDisplayOptions(); | ||
| } | ||
|
|
||
| /** | ||
| * On init, checks for the cookie name provided in the props and if present hides the alert. | ||
| * | ||
| * @returns {void} | ||
| */ | ||
| componentDidMount() { | ||
| if ( Cookies.get( this.props.cookieName ) ) { | ||
| this.setState( { hideAlert: true } ); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Returns the colors and icon to be used based on the type provided to the props. | ||
| * | ||
| * @returns {object} Options with colors and icons to be used. | ||
| */ | ||
| getTypeDisplayOptions() { | ||
| switch ( this.props.type ) { | ||
| case "error": | ||
| return { | ||
| color: colors.$color_alert_error_red, | ||
| background: colors.$color_alert_error_red_light, | ||
| icon: errorIcon( colors.$color_alert_error_red ), | ||
| closeIcon: closeIcon( colors.$color_alert_error_red ), | ||
| }; | ||
| case "success": | ||
| return { | ||
| color: colors.$color_alert_success_green, | ||
| background: colors.$color_alert_success_green_light, | ||
| icon: successIcon( colors.$color_alert_success_green ), | ||
| closeIcon: closeIcon( colors.$color_alert_success_green ), | ||
| }; | ||
| case "warning": | ||
| return { | ||
| color: colors.$color_alert_warning_yellow, | ||
| background: colors.$color_alert_warning_yellow_light, | ||
| icon: warningIcon( colors.$color_alert_warning_yellow ), | ||
| closeIcon: closeIcon( colors.$color_alert_warning_yellow ), | ||
| }; | ||
| case "info": | ||
| default: | ||
| return { | ||
| color: colors.$color_alert_info_blue, | ||
| background: colors.$color_alert_info_blue_light, | ||
| icon: infoIcon( colors.$color_alert_info_blue ), | ||
| closeIcon: closeIcon( colors.$color_alert_info_blue ), | ||
| }; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Called on cross click, hides the alert and saves this setting in a cookie. | ||
| * | ||
| * @returns {void} | ||
| */ | ||
| onCrossClick() { | ||
| Cookies.set( this.props.cookieName, "hide", { expires: 7 } ); | ||
| this.setState( { hideAlert: true } ); | ||
| } | ||
|
|
||
| /** | ||
| * Renders the component. | ||
| * | ||
| * @returns {ReactElement} The rendered component. | ||
| */ | ||
| render() { | ||
| return ( | ||
| ! this.state.hideAlert && | ||
| <AlertBody alertColor={ this.options.color } alertBackground={ this.options.background }> | ||
| <AlertIcon icon={ this.options.icon } /> | ||
| <AlertMessage> | ||
| { this.props.children } | ||
| </AlertMessage> | ||
| { this.props.dismissable && | ||
| <StyledCloseButtonTopRight | ||
| onClick={ this.onCrossClick } | ||
| iconSource={ this.options.closeIcon } | ||
| iconSize="1rem" | ||
| aria-label={ this.props.intl.formatMessage( messages.close ) } | ||
| /> | ||
| } | ||
| </AlertBody> | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| Alert.propTypes = { | ||
| intl: intlShape.isRequired, | ||
| children: PropTypes.any.isRequired, | ||
| dismissable: PropTypes.any.isRequired, | ||
| cookieName: PropTypes.string, | ||
| type: PropTypes.string.isRequired, | ||
| }; | ||
|
|
||
| Alert.defaultProps = { | ||
| cookieName: "", | ||
| }; | ||
|
|
||
| export default injectIntl( Alert ); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,5 +17,8 @@ | |
| }, | ||
| "publishConfig": { | ||
| "access": "public" | ||
| }, | ||
| "dependencies": { | ||
| "grunt": "^1.0.4" | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the Alert was used only in MyYoast,
injectIntlmade sense. Now that is a package component, not sure this is what we'd want to use.For example, when importing and using the Alert in Yoast SEO there would be the need to wrap the component in an
IntlProvidercomponent. Instead, on Yoast SEO we're using@wordpress/i18n. I think this should be changed to use__()but I'd like confirmation from the architects. If so, all the code related toreact-intl(including in App.js) should be removed in favor of@wordpress/i18n.For reference, this is the Alert imported and used in Yoast SEO: