diff --git a/blocks/color-mechanism/index.js b/blocks/color-mechanism/index.js
new file mode 100644
index 0000000000000..6d564304b9871
--- /dev/null
+++ b/blocks/color-mechanism/index.js
@@ -0,0 +1,48 @@
+/**
+ * External dependencies
+ */
+import { find, kebabCase } from 'lodash';
+
+/**
+ * Internal dependencies
+ */
+import './style.scss';
+
+const ALLOWED_COLOR_CONTEXTS = [
+ 'background',
+ 'text',
+];
+
+export const getColorFromAttribute = ( colors ) => ( colorAttribute ) => {
+ if ( ! colorAttribute || colorAttribute[ 0 ] !== '%' ) {
+ return colorAttribute;
+ }
+ const colorObj = find( colors, { name: colorAttribute.slice( 1 ) } );
+ if ( ! colorObj ) {
+ return null;
+ }
+ return colorObj.color;
+};
+export const getAttributeFromColor = ( colors ) => ( color ) => {
+ const colorObj = find( colors, { color } );
+ if ( colorObj ) {
+ return '%' + colorObj.name;
+ }
+ return color;
+};
+
+export function getClassFromAttribute( colorContext, colorAttribute ) {
+ if ( ! colorContext || find( ALLOWED_COLOR_CONTEXTS, colorContext ) ) {
+ if ( window ) {
+ window.console.error( 'An invalid color context was passed.' );
+ }
+ return null;
+ }
+
+ if ( ! colorAttribute || colorAttribute[ 0 ] !== '%' ) {
+ return null;
+ }
+
+ return `has-${ kebabCase( colorAttribute.slice( 1 ) ) }-${ colorContext }-color`;
+}
+
diff --git a/blocks/color-mechanism/style.scss b/blocks/color-mechanism/style.scss
new file mode 100644
index 0000000000000..dd7e469ec5630
--- /dev/null
+++ b/blocks/color-mechanism/style.scss
@@ -0,0 +1,109 @@
+p.has-pale-pink-background-color,
+.wp-block-button.has-pale-pink-background-color .wp-block-button__link {
+ background-color: #f78da7;
+}
+
+p.has-vivid-red-background-color,
+.wp-block-button.has-vivid-red-background-color .wp-block-button__link {
+ background-color: #cf2e2e;
+}
+
+p.has-luminous-vivid-orange-background-color,
+.wp-block-button.has-luminous-vivid-orange-background-color .wp-block-button__link {
+ background-color: #ff6900;
+}
+
+p.has-luminous-vivid-amber-background-color,
+.wp-block-button.has-luminous-vivid-amber-background-color .wp-block-button__link {
+ background-color: #fcb900;
+}
+
+p.has-light-green-cyan-background-color,
+.wp-block-button.has-light-green-cyan-background-color .wp-block-button__link {
+ background-color: #7bdcb5;
+}
+
+p.has-vivid-green-cyan-background-color,
+.wp-block-button.has-vivid-green-cyan-background-color .wp-block-button__link {
+ background-color: #00d084;
+}
+
+p.has-pale-cyan-blue-background-color,
+.wp-block-button.has-pale-cyan-blue-background-color .wp-block-button__link {
+ background-color: #8ed1fc;
+}
+
+p.has-vivid-cyan-blue-background-color,
+.wp-block-button.has-vivid-cyan-blue-background-color .wp-block-button__link {
+ background-color: #0693e3;
+}
+
+p.has-very-light-gray-background-color,
+.wp-block-button.has-very-light-gray-background-color .wp-block-button__link {
+ background-color: #eeeeee;
+}
+
+p.has-cyan-bluish-gray-background-color,
+.wp-block-button.has-cyan-bluish-gray-background-color .wp-block-button__link {
+ background-color: #abb8c3;
+}
+
+p.has-very-dark-gray-background-color,
+.wp-block-button.has-very-dark-gray-background-color .wp-block-button__link {
+ background-color: #313131;
+}
+
+p.has-pale-pink-text-color,
+.wp-block-button.has-pale-pink-text-color .wp-block-button__link {
+ color: #f78da7;
+}
+
+p.has-vivid-red-text-color,
+.wp-block-button.has-vivid-red-text-color .wp-block-button__link {
+ color: #cf2e2e;
+}
+
+p.has-luminous-vivid-orange-text-color,
+.wp-block-button.has-luminous-vivid-orange-text-color .wp-block-button__link {
+ color: #ff6900;
+}
+
+p.has-luminous-vivid-amber-text-color,
+.wp-block-button.has-luminous-vivid-amber-text-color .wp-block-button__link {
+ color: #fcb900;
+}
+
+p.has-light-green-cyan-text-color,
+.wp-block-button.has-light-green-cyan-text-color .wp-block-button__link {
+ color: #7bdcb5;
+}
+
+p.has-vivid-green-cyan-text-color,
+.wp-block-button.has-vivid-green-cyan-text-color .wp-block-button__link {
+ color: #00d084;
+}
+
+p.has-pale-cyan-blue-text-color,
+.wp-block-button.has-pale-cyan-blue-text-color .wp-block-button__link {
+ color: #8ed1fc;
+}
+
+p.has-vivid-cyan-blue-text-color,
+.wp-block-button.has-vivid-cyan-blue-text-color .wp-block-button__link {
+ color: #0693e3;
+}
+
+p.has-very-light-gray-text-color,
+.wp-block-button.has-very-light-gray-text-color .wp-block-button__link {
+ color: #eeeeee;
+}
+
+p.has-cyan-bluish-gray-text-color,
+.wp-block-button.has-cyan-bluish-gray-text-color .wp-block-button__link {
+ color: #abb8c3;
+}
+
+p.has-very-dark-gray-text-color,
+.wp-block-button.has-very-dark-gray-text-color .wp-block-button__link {
+ color: #313131;
+}
diff --git a/blocks/color-palette/index.js b/blocks/color-palette/index.js
index cd540ada1b4c6..0f43d72400d18 100644
--- a/blocks/color-palette/index.js
+++ b/blocks/color-palette/index.js
@@ -23,7 +23,7 @@ export function ColorPalette( { colors, disableCustomColors = false, value, onCh
return (
- { map( colors, ( color ) => {
+ { map( colors, ( { name, color } ) => {
const style = { color: color };
const className = classnames( 'blocks-color-palette__item', { 'is-active': value === color } );
@@ -34,7 +34,7 @@ export function ColorPalette( { colors, disableCustomColors = false, value, onCh
className={ className }
style={ style }
onClick={ applyOrUnset( color ) }
- aria-label={ sprintf( __( 'Color: %s' ), color ) }
+ aria-label={ sprintf( __( 'Color: %s' ), name || color ) }
aria-pressed={ value === color }
/>
diff --git a/blocks/hooks/colors.js b/blocks/hooks/colors.js
new file mode 100644
index 0000000000000..3d8d0d315e16e
--- /dev/null
+++ b/blocks/hooks/colors.js
@@ -0,0 +1,41 @@
+/**
+ * WordPress dependencies
+ */
+import { getWrapperDisplayName } from '@wordpress/element';
+import { addFilter } from '@wordpress/hooks';
+import { withContext } from '@wordpress/components';
+
+/**
+ * Internal dependencies
+ */
+import { getAttributeFromColor, getColorFromAttribute } from '../color-mechanism';
+
+/**
+ * Override the default edit UI to include a new block inspector control for
+ * assigning the custom class name, if block supports custom class name.
+ *
+ * @param {function|Component} BlockEdit Original component.
+ *
+ * @return {string} Wrapped component.
+ */
+export function withColorMechanism( BlockEdit ) {
+ const BlockEditWithColorContext = withContext( 'editor' )(
+ ( settings, props ) => ( settings ? {
+ getAttributeFromColor: getAttributeFromColor( settings.colors ),
+ getColorFromAttribute: getColorFromAttribute( settings.colors ),
+ setColorAttributeByColor: ( attribute ) => ( color ) => {
+ const attributeValue = getAttributeFromColor( settings.colors )( color );
+ props.setAttributes( { [ attribute ]: attributeValue || color } );
+ },
+ } : {} )
+ )( BlockEdit );
+
+ const WrappedBlockEdit = ( props ) => {
+ return ;
+ };
+ WrappedBlockEdit.displayName = getWrapperDisplayName( BlockEdit, 'colorMechanism' );
+
+ return WrappedBlockEdit;
+}
+
+addFilter( 'blocks.BlockEdit', 'core/color-mechanism', withColorMechanism );
diff --git a/blocks/hooks/index.js b/blocks/hooks/index.js
index 0055037fa07f2..e326723ee7f6b 100644
--- a/blocks/hooks/index.js
+++ b/blocks/hooks/index.js
@@ -3,6 +3,7 @@
*/
import './align';
import './anchor';
+import './colors';
import './custom-class-name';
import './deprecated';
import './generated-class-name';
diff --git a/blocks/library/button/index.js b/blocks/library/button/index.js
index fdcf21f6f3844..e396c87a667ca 100644
--- a/blocks/library/button/index.js
+++ b/blocks/library/button/index.js
@@ -1,3 +1,8 @@
+/**
+ * External dependencies
+ */
+import classnames from 'classnames';
+
/**
* WordPress dependencies
*/
@@ -17,6 +22,7 @@ import BlockAlignmentToolbar from '../../block-alignment-toolbar';
import ColorPalette from '../../color-palette';
import ContrastChecker from '../../contrast-checker';
import InspectorControls from '../../inspector-controls';
+import { getClassFromAttribute } from '../../color-mechanism';
const { getComputedStyle } = window;
@@ -61,6 +67,8 @@ class ButtonBlock extends Component {
setAttributes,
isSelected,
className,
+ getColorFromAttribute,
+ setColorAttributeByColor,
} = this.props;
const {
@@ -73,13 +81,18 @@ class ButtonBlock extends Component {
clear,
} = attributes;
+ const textColorClass = getClassFromAttribute( 'text', textColor );
+ const backgroundColorClass = getClassFromAttribute( 'background', color );
+ const textColorValue = getColorFromAttribute( textColor );
+ const backgroundColorValue = getColorFromAttribute( color );
+
return [
isSelected && (
),
-
+
-
+
setAttributes( { color: colorValue } ) }
+ value={ backgroundColorValue }
+ onChange={ setColorAttributeByColor( 'color' ) }
/>
-
+
setAttributes( { textColor: colorValue } ) }
+ value={ textColorValue }
+ onChange={ setColorAttributeByColor( 'textColor' ) }
/>
{ this.nodeRef && }
}
@@ -201,16 +214,18 @@ export const settings = {
save( { attributes } ) {
const { url, text, title, align, color, textColor } = attributes;
+ const backgroundClass = getClassFromAttribute( 'background', color );
+ const textClass = getClassFromAttribute( 'text', textColor );
const buttonStyle = {
- backgroundColor: color,
- color: textColor,
+ backgroundColor: ! backgroundClass ? color : undefined,
+ color: ! textClass ? textColor : undefined,
};
const linkClass = 'wp-block-button__link';
return (
-
+
{ text }
diff --git a/blocks/library/paragraph/editor.scss b/blocks/library/paragraph/editor.scss
index a50c04177658f..d6ce95eae740f 100644
--- a/blocks/library/paragraph/editor.scss
+++ b/blocks/library/paragraph/editor.scss
@@ -1,3 +1,3 @@
-.editor-block-list__block:not( .is-multi-selected ) .wp-block-paragraph {
+.editor-block-list__block:not( .is-multi-selected ) .wp-block-paragraph:not( .has-background ) {
background: white;
}
diff --git a/blocks/library/paragraph/index.js b/blocks/library/paragraph/index.js
index f31fa3d1374d6..c5c32c9cc1c9c 100644
--- a/blocks/library/paragraph/index.js
+++ b/blocks/library/paragraph/index.js
@@ -31,6 +31,7 @@ import RichText from '../../rich-text';
import InspectorControls from '../../inspector-controls';
import ColorPalette from '../../color-palette';
import ContrastChecker from '../../contrast-checker';
+import { getClassFromAttribute } from '../../color-mechanism';
const { getComputedStyle } = window;
@@ -89,6 +90,8 @@ class ParagraphBlock extends Component {
isSelected,
mergeBlocks,
onReplace,
+ getColorFromAttribute,
+ setColorAttributeByColor,
} = this.props;
const {
@@ -104,6 +107,11 @@ class ParagraphBlock extends Component {
const className = dropCap ? 'has-drop-cap' : null;
+ const textColorClass = getClassFromAttribute( 'text', textColor );
+ const backgroundColorClass = getClassFromAttribute( 'background', backgroundColor );
+ const textColorValue = getColorFromAttribute( textColor );
+ const backgroundColorValue = getColorFromAttribute( backgroundColor );
+
return [
isSelected && (
@@ -133,22 +141,22 @@ class ParagraphBlock extends Component {
allowReset
/>
-
+
setAttributes( { backgroundColor: colorValue } ) }
+ value={ backgroundColorValue }
+ onChange={ setColorAttributeByColor( 'backgroundColor' ) }
/>
-
+
setAttributes( { textColor: colorValue } ) }
+ value={ textColorValue }
+ onChange={ setColorAttributeByColor( 'textColor' ) }
/>
{ this.nodeRef && = 18 }
/> }
@@ -169,10 +177,12 @@ class ParagraphBlock extends Component {
tagName="p"
className={ classnames( 'wp-block-paragraph', className, {
'has-background': backgroundColor,
+ [ backgroundColorClass ]: backgroundColorClass,
+ [ textColorClass ]: textColorClass,
} ) }
style={ {
- backgroundColor: backgroundColor,
- color: textColor,
+ backgroundColor: ! backgroundColorClass ? backgroundColorValue : undefined,
+ color: ! textColorClass ? textColorValue : undefined,
fontSize: fontSize ? fontSize + 'px' : undefined,
textAlign: align,
} }
@@ -313,14 +323,19 @@ export const settings = {
save( { attributes } ) {
const { width, align, content, dropCap, backgroundColor, textColor, fontSize } = attributes;
+ const backgroundClass = getClassFromAttribute( 'background', backgroundColor );
+ const textClass = getClassFromAttribute( 'text', textColor );
+
const className = classnames( {
[ `align${ width }` ]: width,
'has-background': backgroundColor,
'has-drop-cap': dropCap,
+ [ backgroundClass ]: backgroundClass,
+ [ textClass ]: textClass,
} );
const styles = {
- backgroundColor: backgroundColor,
- color: textColor,
+ backgroundColor: ! backgroundClass ? backgroundColor : undefined,
+ color: ! textClass ? textColor : undefined,
fontSize: fontSize,
textAlign: align,
};
diff --git a/editor/components/provider/index.js b/editor/components/provider/index.js
index 1258e274e21d1..53d8a12f3f3dc 100644
--- a/editor/components/provider/index.js
+++ b/editor/components/provider/index.js
@@ -33,17 +33,48 @@ import store from '../../store';
const DEFAULT_SETTINGS = {
alignWide: false,
colors: [
- '#f78da7',
- '#cf2e2e',
- '#ff6900',
- '#fcb900',
- '#7bdcb5',
- '#00d084',
- '#8ed1fc',
- '#0693e3',
- '#eee',
- '#abb8c3',
- '#313131',
+ { name: 'pale pink',
+ color: '#f78da7',
+ },
+ { name: 'vivid red',
+ color: '#cf2e2e',
+ },
+ {
+ name: 'luminous vivid orange',
+ color: '#ff6900',
+ },
+ {
+ name: 'luminous vivid amber',
+ color: '#fcb900',
+ },
+ {
+ name: 'light green cyan',
+ color: '#7bdcb5',
+ },
+ {
+ name: 'vivid green cyan',
+ color: '#00d084',
+ },
+ {
+ name: 'pale cyan-blue',
+ color: '#8ed1fc',
+ },
+ {
+ name: 'vivid cyan-blue',
+ color: '#0693e3',
+ },
+ {
+ name: 'very light gray',
+ color: '#eeeeee',
+ },
+ {
+ name: 'cyan-bluish gray',
+ color: '#abb8c3',
+ },
+ {
+ name: 'very dark gray',
+ color: '#313131',
+ },
],
// This is current max width of the block inner area