diff --git a/packages/block-library/src/pullquote/edit.js b/packages/block-library/src/pullquote/edit.js
new file mode 100644
index 0000000000000..0f042f5e0fa0e
--- /dev/null
+++ b/packages/block-library/src/pullquote/edit.js
@@ -0,0 +1,145 @@
+/**
+ * External dependencies
+ */
+import classnames from 'classnames';
+import { includes, map } from 'lodash';
+
+/**
+ * WordPress dependencies
+ */
+import { __ } from '@wordpress/i18n';
+import {
+ Component,
+ Fragment,
+} from '@wordpress/element';
+import {
+ RichText,
+ ContrastChecker,
+ InspectorControls,
+ withColors,
+ PanelColorSettings,
+} from '@wordpress/editor';
+
+export const SOLID_COLOR_STYLE_NAME = 'solid-color';
+export const SOLID_COLOR_CLASS = `is-style-${ SOLID_COLOR_STYLE_NAME }`;
+
+export const toRichTextValue = ( value ) => map( value, ( ( subValue ) => subValue.children ) );
+export const fromRichTextValue = ( value ) => map( value, ( subValue ) => ( {
+ children: subValue,
+} ) );
+
+class PullQuoteEdit extends Component {
+ constructor( props ) {
+ super( props );
+
+ this.wasTextColorAutomaticallyComputed = false;
+ this.pullQuoteMainColorSetter = this.pullQuoteMainColorSetter.bind( this );
+ this.pullQuoteTextColorSetter = this.pullQuoteTextColorSetter.bind( this );
+ }
+
+ pullQuoteMainColorSetter( colorValue ) {
+ const { colorUtils, textColor, setTextColor, setMainColor } = this.props;
+ setMainColor( colorValue );
+ if ( ! textColor.color || this.wasTextColorAutomaticallyComputed ) {
+ this.wasTextColorAutomaticallyComputed = true;
+ setTextColor( colorUtils.getMostReadableColor( colorValue ) );
+ }
+ }
+
+ pullQuoteTextColorSetter( colorValue ) {
+ const { setTextColor } = this.props;
+ setTextColor( colorValue );
+ this.wasTextColorAutomaticallyComputed = false;
+ }
+
+ render() {
+ const {
+ attributes,
+ mainColor,
+ textColor,
+ setAttributes,
+ isSelected,
+ className,
+ } = this.props;
+
+ const { value, citation } = attributes;
+
+ const isSolidColorStyle = includes( className, SOLID_COLOR_CLASS );
+ const figureStyle = isSolidColorStyle ?
+ { backgroundColor: mainColor.color } :
+ { borderColor: mainColor.color };
+ const blockquoteStyle = {
+ color: textColor.color,
+ };
+ const blockquoteClasses = textColor.color ? classnames( 'has-text-color', {
+ [ textColor.class ]: textColor.class,
+ } ) : undefined;
+ return (
+
+
+
+ setAttributes( {
+ value: fromRichTextValue( nextValue ),
+ } )
+ }
+ /* translators: the text of the quotation */
+ placeholder={ __( 'Write quote…' ) }
+ wrapperClassName="block-library-pullquote__content"
+ />
+ { ( ! RichText.isEmpty( citation ) || isSelected ) && (
+ setAttributes( {
+ citation: nextCitation,
+ } )
+ }
+ className="wp-block-pullquote__citation"
+ />
+ ) }
+
+
+
+
+ { isSolidColorStyle && (
+
+ ) }
+
+
+
+ );
+ }
+}
+
+export default withColors( { mainColor: 'background-color', textColor: 'color' } )(
+ PullQuoteEdit
+);
diff --git a/packages/block-library/src/pullquote/editor.scss b/packages/block-library/src/pullquote/editor.scss
index 075f2ff5aa56f..a05314749bf98 100644
--- a/packages/block-library/src/pullquote/editor.scss
+++ b/packages/block-library/src/pullquote/editor.scss
@@ -22,7 +22,25 @@
& blockquote > .block-library-pullquote__content .editor-rich-text__tinymce[data-is-empty="true"]::before,
& blockquote > .editor-rich-text p {
- font-size: 24px;
+ font-size: 28px;
line-height: 1.6;
}
}
+
+.wp-block-pullquote.is-style-solid-color {
+ margin-left: 0;
+ margin-right: 0;
+
+ & blockquote > .editor-rich-text p {
+ font-size: 32px;
+ }
+
+ .wp-block-pullquote__citation {
+ text-transform: none;
+ font-style: normal;
+ }
+}
+
+.wp-block-pullquote .wp-block-pullquote__citation {
+ color: inherit;
+}
diff --git a/packages/block-library/src/pullquote/index.js b/packages/block-library/src/pullquote/index.js
index bd4ac84feb8d8..1c611138ee477 100644
--- a/packages/block-library/src/pullquote/index.js
+++ b/packages/block-library/src/pullquote/index.js
@@ -1,20 +1,29 @@
/**
* External dependencies
*/
-import { map } from 'lodash';
+import classnames from 'classnames';
+import { get, includes } from 'lodash';
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import {
+ getColorClassName,
RichText,
+ getColorObjectByAttributeValues,
} from '@wordpress/editor';
+import {
+ select,
+} from '@wordpress/data';
+
+import {
+ default as edit,
+ SOLID_COLOR_STYLE_NAME,
+ SOLID_COLOR_CLASS,
+ toRichTextValue,
+} from './edit';
-const toRichTextValue = ( value ) => map( value, ( ( subValue ) => subValue.children ) );
-const fromRichTextValue = ( value ) => map( value, ( subValue ) => ( {
- children: subValue,
-} ) );
const blockAttributes = {
value: {
type: 'array',
@@ -31,6 +40,18 @@ const blockAttributes = {
source: 'children',
selector: 'cite',
},
+ mainColor: {
+ type: 'string',
+ },
+ customMainColor: {
+ type: 'string',
+ },
+ textColor: {
+ type: 'string',
+ },
+ customTextColor: {
+ type: 'string',
+ },
};
export const name = 'core/pullquote';
@@ -47,52 +68,53 @@ export const settings = {
attributes: blockAttributes,
+ styles: [
+ { name: 'default', label: __( 'Regular' ), isDefault: true },
+ { name: SOLID_COLOR_STYLE_NAME, label: __( 'Solid Color' ) },
+ ],
+
supports: {
- align: true,
+ align: [ 'left', 'right', 'wide', 'full' ],
},
- edit( { attributes, setAttributes, isSelected, className } ) {
- const { value, citation } = attributes;
-
- return (
-
-
- setAttributes( {
- value: fromRichTextValue( nextValue ),
- } )
- }
- /* translators: the text of the quotation */
- placeholder={ __( 'Write quote…' ) }
- wrapperClassName="block-library-pullquote__content"
- />
- { ( ! RichText.isEmpty( citation ) || isSelected ) && (
- setAttributes( {
- citation: nextCitation,
- } )
- }
- className="wp-block-pullquote__citation"
- />
- ) }
-
-
- );
- },
+ edit,
save( { attributes } ) {
- const { value, citation } = attributes;
-
+ const { mainColor, customMainColor, textColor, customTextColor, value, citation, className } = attributes;
+ const isSolidColorStyle = includes( className, SOLID_COLOR_CLASS );
+
+ let figureClass, figureStyles;
+ // Is solid color style
+ if ( isSolidColorStyle ) {
+ figureClass = getColorClassName( 'background-color', mainColor );
+ if ( ! figureClass ) {
+ figureStyles = {
+ backgroundColor: customMainColor,
+ };
+ }
+ // Is normal style and a custom color is being used ( we can set a style directly with its value)
+ } else if ( customMainColor ) {
+ figureStyles = {
+ borderColor: customMainColor,
+ };
+ // Is normal style and a named color is being used, we need to retrieve the color value to set the style,
+ // as there is no expectation that themes create classes that set border colors.
+ } else if ( mainColor ) {
+ const colors = get( select( 'core/editor' ).getEditorSettings(), [ 'colors' ], [] );
+ const colorObject = getColorObjectByAttributeValues( colors, mainColor );
+ figureStyles = {
+ borderColor: colorObject.color,
+ };
+ }
+
+ const blockquoteTextColorClass = getColorClassName( 'color', textColor );
+ const blockquoteClasses = textColor || customTextColor ? classnames( 'has-text-color', {
+ [ blockquoteTextColorClass ]: blockquoteTextColorClass,
+ } ) : undefined;
+ const blockquoteStyle = blockquoteTextColorClass ? undefined : { color: customTextColor };
return (
-
-
+
+
{ ! RichText.isEmpty( citation ) && }
diff --git a/packages/block-library/src/pullquote/style.scss b/packages/block-library/src/pullquote/style.scss
index 7bc4b66cdc440..388e240248421 100644
--- a/packages/block-library/src/pullquote/style.scss
+++ b/packages/block-library/src/pullquote/style.scss
@@ -12,7 +12,7 @@
}
p {
- font-size: 24px;
+ font-size: 28px;
line-height: 1.6;
}
@@ -20,4 +20,37 @@
footer {
position: relative;
}
+ .has-text-color a {
+ color: inherit;
+ }
+}
+
+.wp-block-pullquote:not(.is-style-solid-color) {
+ background: none;
+}
+
+.wp-block-pullquote.is-style-solid-color {
+ border: none;
+ blockquote {
+ margin-left: auto;
+ margin-right: auto;
+ text-align: left;
+
+ max-width: 60%;
+
+ p {
+ margin-top: 0;
+ margin-bottom: 0;
+ font-size: 32px;
+ }
+
+ cite {
+ text-transform: none;
+ font-style: normal;
+ }
+ }
+}
+
+.wp-block-pullquote cite {
+ color: inherit;
}
diff --git a/packages/block-library/src/pullquote/theme.scss b/packages/block-library/src/pullquote/theme.scss
index 178d8b0fd2763..41f7ba2a45ee8 100644
--- a/packages/block-library/src/pullquote/theme.scss
+++ b/packages/block-library/src/pullquote/theme.scss
@@ -9,6 +9,6 @@
color: $dark-gray-600;
text-transform: uppercase;
font-size: $default-font-size;
- font-style: italic;
+ font-style: normal;
}
}
diff --git a/packages/editor/src/components/colors/utils.js b/packages/editor/src/components/colors/utils.js
index 36dc77385a82b..29ab15f30e731 100644
--- a/packages/editor/src/components/colors/utils.js
+++ b/packages/editor/src/components/colors/utils.js
@@ -1,7 +1,8 @@
/**
* External dependencies
*/
-import { find, kebabCase } from 'lodash';
+import { find, kebabCase, map } from 'lodash';
+import tinycolor from 'tinycolor2';
/**
* Provided an array of color objects as set by the theme or by the editor defaults,
@@ -56,3 +57,18 @@ export function getColorClassName( colorContextName, colorSlug ) {
return `has-${ kebabCase( colorSlug ) }-${ colorContextName }`;
}
+
+/**
+* Given an array of color objects and a color value returns the color value of the most readable color in the array.
+*
+* @param {Array} colors Array of color objects as set by the theme or by the editor defaults.
+* @param {?string} colorValue A string containing the color value.
+*
+* @return {string} String with the color value of the most readable color.
+*/
+export function getMostReadableColor( colors, colorValue ) {
+ return tinycolor.mostReadable(
+ colorValue,
+ map( colors, 'color' )
+ ).toHexString();
+}
diff --git a/packages/editor/src/components/colors/with-colors.js b/packages/editor/src/components/colors/with-colors.js
index 3bf1508872ba2..3d1bccc8c2656 100644
--- a/packages/editor/src/components/colors/with-colors.js
+++ b/packages/editor/src/components/colors/with-colors.js
@@ -13,7 +13,7 @@ import { compose, createHigherOrderComponent } from '@wordpress/compose';
/**
* Internal dependencies
*/
-import { getColorClassName, getColorObjectByColorValue, getColorObjectByAttributeValues } from './utils';
+import { getColorClassName, getColorObjectByColorValue, getColorObjectByAttributeValues, getMostReadableColor } from './utils';
const DEFAULT_COLORS = [];
@@ -54,10 +54,18 @@ export default ( ...args ) => {
super( props );
this.setters = this.createSetters();
+ this.colorUtils = {
+ getMostReadableColor: this.getMostReadableColor.bind( this ),
+ };
this.state = {};
}
+ getMostReadableColor( colorValue ) {
+ const { colors } = this.props;
+ return getMostReadableColor( colors, colorValue );
+ }
+
createSetters() {
return reduce( colorMap, ( settersAccumulator, colorContext, colorAttributeName ) => {
const upperFirstColorAttributeName = upperFirst( colorAttributeName );
@@ -113,6 +121,7 @@ export default ( ...args ) => {
colors: undefined,
...this.state,
...this.setters,
+ colorUtils: this.colorUtils,
} }
/>
);