diff --git a/blocks/color-palette/index.js b/blocks/color-palette/index.js
index 22f6cdc8eabd3a..cb1d9417d1377c 100644
--- a/blocks/color-palette/index.js
+++ b/blocks/color-palette/index.js
@@ -24,7 +24,7 @@ export function ColorPalette( { colors, disableCustomColors = false, value, onCh
return (
- { map( colors, ( color ) => {
+ { map( colors, ( { color } ) => {
const style = { color: color };
const className = classnames( 'blocks-color-palette__item', { 'is-active': value === color } );
diff --git a/blocks/color-palette/test/index.js b/blocks/color-palette/test/index.js
index 96ddc339cdf94a..f8bc82d7ce8e7e 100644
--- a/blocks/color-palette/test/index.js
+++ b/blocks/color-palette/test/index.js
@@ -9,7 +9,7 @@ import { shallow } from 'enzyme';
import { ColorPalette } from '../';
describe( 'ColorPalette', () => {
- const colors = [ 'red', 'white', 'blue' ];
+ const colors = [ { name: 'red', color: 'red' }, { name: 'white', color: 'white' }, { name: 'blue', color: 'blue' } ];
const currentColor = 'red';
const onChange = jest.fn();
diff --git a/blocks/colors/index.js b/blocks/colors/index.js
new file mode 100644
index 00000000000000..29b52a42d88e56
--- /dev/null
+++ b/blocks/colors/index.js
@@ -0,0 +1,2 @@
+export { getColorClass } from './utils';
+export { default as withColors } from './with-colors';
diff --git a/blocks/colors/utils.js b/blocks/colors/utils.js
new file mode 100644
index 00000000000000..6c7d7b8814b413
--- /dev/null
+++ b/blocks/colors/utils.js
@@ -0,0 +1,59 @@
+/**
+ * External dependencies
+ */
+import { find, kebabCase } from 'lodash';
+
+/**
+ * Returns the color value based on an array of named colors and the namedColor or the customColor value.
+ *
+ * @param {Array} colors Array of color objects containing the "name" and "color" value as properties.
+ * @param {?string} namedColor A string containing the color name.
+ * @param {?string} customColor A string containing the customColor value.
+ *
+ * @return {?string} If namedColor is passed and the name is found in colors it returns the color for that name.
+ * Otherwise, the customColor parameter is returned.
+ */
+export const getColorValue = ( colors, namedColor, customColor ) => {
+ if ( namedColor ) {
+ const colorObj = find( colors, { name: namedColor } );
+ return colorObj && colorObj.color;
+ }
+ if ( customColor ) {
+ return customColor;
+ }
+};
+
+/**
+ * Returns a function that receives the color value and sets it using the attribute for named colors or for custom colors.
+ *
+ * @param {Array} colors Array of color objects containing the "name" and "color" value as properties.
+ * @param {string} colorAttributeName Name of the attribute where named colors are stored.
+ * @param {string} customColorAttributeName Name of the attribute where custom colors are stored.
+ * @param {string} setAttributes A function that receives an object with the attributes to set.
+ *
+ * @return {function} A function that receives the color value and sets the attributes necessary to correctly store it.
+ */
+export const setColorValue = ( colors, colorAttributeName, customColorAttributeName, setAttributes ) =>
+ ( colorValue ) => {
+ const colorObj = find( colors, { color: colorValue } );
+ setAttributes( {
+ [ colorAttributeName ]: colorObj && colorObj.name ? colorObj.name : undefined,
+ [ customColorAttributeName ]: colorObj && colorObj.name ? undefined : colorValue,
+ } );
+ };
+
+/**
+ * Returns a class based on the context a color is being used and its name.
+ *
+ * @param {string} colorContextName Context/place where color is being used e.g: background, text etc...
+ * @param {string} colorName Name of the color.
+ *
+ * @return {string} String with the class corresponding to the color in the provided context.
+ */
+export function getColorClass( colorContextName, colorName ) {
+ if ( ! colorContextName || ! colorName ) {
+ return;
+ }
+
+ return `has-${ kebabCase( colorName ) }-${ colorContextName }`;
+}
diff --git a/blocks/colors/with-colors.js b/blocks/colors/with-colors.js
new file mode 100644
index 00000000000000..03f06f30ef65be
--- /dev/null
+++ b/blocks/colors/with-colors.js
@@ -0,0 +1,42 @@
+/**
+ * External dependencies
+ */
+import { get } from 'lodash';
+
+/**
+ * WordPress dependencies
+ */
+import { createHigherOrderComponent } from '@wordpress/element';
+
+/**
+ * Internal dependencies
+ */
+import { getColorValue, getColorClass, setColorValue } from './utils';
+import { withEditorSettings } from '../editor-settings';
+
+/**
+ * Higher-order component, which handles color logic for class generation
+ * color value, retrieval and color attribute setting.
+ *
+ * @param {WPElement} WrappedComponent The wrapped component.
+ *
+ * @return {Component} Component with a new colors prop.
+ */
+export default createHigherOrderComponent(
+ withEditorSettings(
+ ( settings, props ) => {
+ const colors = get( settings, [ 'colors' ], [] );
+ return {
+ initializeColor: ( { colorContext, colorAttribute, customColorAttribute } ) => ( {
+ value: getColorValue(
+ colors,
+ props.attributes[ colorAttribute ],
+ props.attributes[ customColorAttribute ]
+ ),
+ class: getColorClass( colorContext, props.attributes[ colorAttribute ] ),
+ set: setColorValue( colors, colorAttribute, customColorAttribute, props.setAttributes ),
+ } ),
+ };
+ } ),
+ 'withColors'
+);
diff --git a/blocks/editor-settings/index.js b/blocks/editor-settings/index.js
index 72639239f48369..d6e248a16772ef 100644
--- a/blocks/editor-settings/index.js
+++ b/blocks/editor-settings/index.js
@@ -15,17 +15,49 @@ import { createContext, createHigherOrderComponent } from '@wordpress/element';
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
diff --git a/blocks/index.js b/blocks/index.js
index bb306e2dfbe3e9..182be4f09f99f0 100644
--- a/blocks/index.js
+++ b/blocks/index.js
@@ -14,6 +14,7 @@ import './hooks';
// and then stored as objects in state, from which it is then rendered for editing.
export * from './api';
export * from './autocompleters';
+export * from './colors';
export { default as editorMediaUpload } from './editor-media-upload';
export { default as AlignmentToolbar } from './alignment-toolbar';
diff --git a/core-blocks/index.js b/core-blocks/index.js
index e9a1c5374675a0..8c2600219d6ff0 100644
--- a/core-blocks/index.js
+++ b/core-blocks/index.js
@@ -11,6 +11,7 @@ import { deprecated } from '@wordpress/utils';
/**
* Internal dependencies
*/
+import './style.scss';
import * as paragraph from './paragraph';
import * as image from './image';
import * as heading from './heading';
diff --git a/core-blocks/paragraph/index.js b/core-blocks/paragraph/index.js
index 30f71c9f0765e5..41ca5bee2baea0 100644
--- a/core-blocks/paragraph/index.js
+++ b/core-blocks/paragraph/index.js
@@ -11,6 +11,7 @@ import { __ } from '@wordpress/i18n';
import {
concatChildren,
Component,
+ compose,
Fragment,
RawHTML,
} from '@wordpress/element';
@@ -26,6 +27,8 @@ import {
import {
createBlock,
blockAutocompleter,
+ getColorClass,
+ withColors,
userAutocompleter,
AlignmentToolbar,
BlockAlignmentToolbar,
@@ -128,6 +131,7 @@ class ParagraphBlock extends Component {
mergeBlocks,
onReplace,
className,
+ initializeColor,
fallbackBackgroundColor,
fallbackTextColor,
fallbackFontSize,
@@ -138,12 +142,20 @@ class ParagraphBlock extends Component {
content,
dropCap,
placeholder,
- backgroundColor,
- textColor,
width,
} = attributes;
const fontSize = this.getFontSize();
+ const textColor = initializeColor( {
+ colorContext: 'color',
+ colorAttribute: 'textColor',
+ customColorAttribute: 'customTextColor',
+ } );
+ const backgroundColor = initializeColor( {
+ colorContext: 'background-color',
+ colorAttribute: 'backgroundColor',
+ customColorAttribute: 'customBackgroundColor',
+ } );
return (
@@ -200,22 +212,22 @@ class ParagraphBlock extends Component {
onChange={ this.toggleDropCap }
/>
-
+
setAttributes( { backgroundColor: colorValue } ) }
+ value={ backgroundColor.value }
+ onChange={ backgroundColor.set }
/>
-
+
setAttributes( { textColor: colorValue } ) }
+ value={ textColor.value }
+ onChange={ textColor.set }
/>
{ content };
},
migrate( attributes ) {
- if ( isFinite( attributes.fontSize ) ) {
- return omit( {
- ...attributes,
- customFontSize: attributes.fontSize,
- }, 'fontSize' );
- }
- return attributes;
+ return omit( {
+ ...attributes,
+ customFontSize: isFinite( attributes.fontSize ) ? attributes.fontSize : undefined,
+ customTextColor: attributes.textColor && '#' === attributes.textColor[ 0 ] ? attributes.textColor : undefined,
+ customBackgroundColor: attributes.backgroundColor && '#' === attributes.backgroundColor[ 0 ] ? attributes.backgroundColor : undefined,
+ }, [ 'fontSize', 'textColor', 'backgroundColor' ] );
},
},
{
@@ -408,7 +427,10 @@ export const settings = {
}
},
- edit: FallbackStyles( ParagraphBlock ),
+ edit: compose(
+ withColors,
+ FallbackStyles,
+ )( ParagraphBlock ),
save( { attributes } ) {
const {
@@ -418,21 +440,29 @@ export const settings = {
dropCap,
backgroundColor,
textColor,
+ customBackgroundColor,
+ customTextColor,
fontSize,
customFontSize,
} = attributes;
+ const textClass = getColorClass( 'color', textColor );
+ const backgroundClass = getColorClass( 'background-color', backgroundColor );
+ const fontSizeClass = fontSize && FONT_SIZES[ fontSize ] && `is-${ fontSize }-text`;
+
const className = classnames( {
[ `align${ width }` ]: width,
- 'has-background': backgroundColor,
+ 'has-background': backgroundColor || customBackgroundColor,
'has-drop-cap': dropCap,
- [ `is-${ fontSize }-text` ]: fontSize && FONT_SIZES[ fontSize ],
+ [ fontSizeClass ]: fontSizeClass,
+ [ textClass ]: textClass,
+ [ backgroundClass ]: backgroundClass,
} );
const styles = {
- backgroundColor: backgroundColor,
- color: textColor,
- fontSize: ! fontSize && customFontSize ? customFontSize : undefined,
+ backgroundColor: backgroundClass ? undefined : customBackgroundColor,
+ color: textClass ? undefined : customTextColor,
+ fontSize: fontSizeClass ? undefined : customFontSize,
textAlign: align,
};
diff --git a/core-blocks/style.scss b/core-blocks/style.scss
new file mode 100644
index 00000000000000..fa6cef63fb6cb5
--- /dev/null
+++ b/core-blocks/style.scss
@@ -0,0 +1,87 @@
+.has-pale-pink-background-color {
+ background-color: #f78da7;
+}
+
+.has-vivid-red-background-color {
+ background-color: #cf2e2e;
+}
+
+.has-luminous-vivid-orange-background-color {
+ background-color: #ff6900;
+}
+
+.has-luminous-vivid-amber-background-color {
+ background-color: #fcb900;
+}
+
+.has-light-green-cyan-background-color {
+ background-color: #7bdcb5;
+}
+
+.has-vivid-green-cyan-background-color {
+ background-color: #00d084;
+}
+
+.has-pale-cyan-blue-background-color {
+ background-color: #8ed1fc;
+}
+
+.has-vivid-cyan-blue-background-color {
+ background-color: #0693e3;
+}
+
+.has-very-light-gray-background-color {
+ background-color: #eeeeee;
+}
+
+.has-cyan-bluish-gray-background-color {
+ background-color: #abb8c3;
+}
+
+.has-very-dark-gray-background-color {
+ background-color: #313131;
+}
+
+.has-pale-pink-color {
+ color: #f78da7;
+}
+
+.has-vivid-red-color {
+ color: #cf2e2e;
+}
+
+.has-luminous-vivid-orange-color {
+ color: #ff6900;
+}
+
+.has-luminous-vivid-amber-color {
+ color: #fcb900;
+}
+
+.has-light-green-cyan-color {
+ color: #7bdcb5;
+}
+
+.has-vivid-green-cyan-color {
+ color: #00d084;
+}
+
+.has-pale-cyan-blue-color {
+ color: #8ed1fc;
+}
+
+.has-vivid-cyan-blue-color {
+ color: #0693e3;
+}
+
+.has-very-light-gray-color {
+ color: #eeeeee;
+}
+
+.has-cyan-bluish-gray-color {
+ color: #abb8c3;
+}
+
+.has-very-dark-gray-color {
+ color: #313131;
+}
diff --git a/docs/extensibility/theme-support.md b/docs/extensibility/theme-support.md
index 353626a856c557..07d8423c9569f4 100644
--- a/docs/extensibility/theme-support.md
+++ b/docs/extensibility/theme-support.md
@@ -9,10 +9,22 @@ To opt-in for one of these features, call `add_theme_support` in the `functions.
```php
function mytheme_setup_theme_supported_features() {
add_theme_support( 'editor-color-palette',
- '#a156b4',
- '#d0a5db',
- '#eee',
- '#444'
+ array(
+ 'name' => 'strong magenta',
+ 'color' => '#a156b4',
+ ),
+ array(
+ 'name' => 'light grayish magenta',
+ 'color' => '#d0a5db',
+ ),
+ array(
+ 'name' => 'very light gray',
+ 'color' => '#eee',
+ ),
+ array(
+ 'name' => 'very dark gray',
+ 'color' => '#444',
+ )
);
}
@@ -35,15 +47,41 @@ Different blocks have the possibility of customizing colors. Gutenberg provides
```php
add_theme_support( 'editor-color-palette',
- '#a156b4',
- '#d0a5db',
- '#eee',
- '#444'
+ array(
+ 'name' => 'strong magenta',
+ 'color' => '#a156b4',
+ ),
+ array(
+ 'name' => 'light grayish magenta',
+ 'color' => '#d0a5db',
+ ),
+ array(
+ 'name' => 'very light gray',
+ 'color' => '#eee',
+ ),
+ array(
+ 'name' => 'very dark gray',
+ 'color' => '#444',
+ )
);
```
The colors will be shown in order on the palette, and there's no limit to how many can be specified.
+Themes are responsible for creating the classes that apply the colors in different contexts. Core blocks use "color" and "background-color" contexts. So to correctly apply "strong magenta" to all contexts of core blocks a theme should implement the following classes:
+
+```css
+.has-strong-magenta-background-color {
+ background-color: #313131;
+}
+
+.has-strong-magenta-color {
+ color: #f78da7;
+}
+```
+
+The class name is built appending 'has-', followed by the class name *using* kebab case and ending with the context name.
+
### Disabling custom colors in block Color Palettes
By default, the color palette offered to blocks, allows the user to select a custom color different from the editor or theme default colors.
diff --git a/edit-post/index.js b/edit-post/index.js
index 9ef27883d225ab..19cfe5d6b024f3 100644
--- a/edit-post/index.js
+++ b/edit-post/index.js
@@ -1,7 +1,13 @@
+/**
+ * External dependencies
+ */
+import { get, isString, some } from 'lodash';
+
/**
* WordPress dependencies
*/
import { render, unmountComponentAtNode } from '@wordpress/element';
+import { deprecated } from '@wordpress/utils';
/**
* Internal dependencies
@@ -65,8 +71,21 @@ export function initializeEditor( id, post, settings ) {
);
}
+ let migratedSettings;
+ const colors = get( settings, [ 'colors' ] );
+ if ( some( colors, isString ) ) {
+ migratedSettings = {
+ ...settings,
+ colors: colors.map( ( color ) => isString( color ) ? { color } : color ),
+ };
+ deprecated( 'Setting theme colors without names', {
+ version: '2.9',
+ alternative: 'add_theme_support( \'colors\', array( \'name\' => \'my-color\', \'color\': \'#ff0\' );' }
+ );
+ }
+
render(
- ,
+ ,
target
);