Skip to content

Commit

Permalink
Add link color as an element mechanism.
Browse files Browse the repository at this point in the history
  • Loading branch information
jorgefilipecosta committed May 17, 2021
1 parent e4a72bc commit 994e5e3
Show file tree
Hide file tree
Showing 13 changed files with 333 additions and 100 deletions.
65 changes: 65 additions & 0 deletions lib/block-supports/elements.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php
/**
* Elements styles block support.
*
* @package gutenberg
*/

/**
* Render the elements stylesheet.
*
* @param string $block_content Rendered block content.
* @param array $block Block object.
* @return string Filtered block content.
*/
function gutenberg_render_elements_support( $block_content, $block ) {
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] );
$link_color = _wp_array_get( $block['attrs'], array( 'style', 'elements', 'link', 'color', 'text' ), null );

/*
* For now we only care about link color.
* This code in the future when we have a public API
* should take advantage of WP_Theme_JSON::compute_style_properties
* and work for any element and style.
*/
if ( null === $link_color ) {
return $block_content;
}

$class_name = 'wp-elements-' . uniqid();

if ( strpos( $link_color, 'var:preset|color|' ) !== false ) {
// Get the name from the string and add proper styles.
$index_to_splice = strrpos( $link_color, '|' ) + 1;
$link_color_name = substr( $link_color, $index_to_splice );
$link_color = "var(--wp--preset--color--$link_color_name)";
}
$link_color_declaration = esc_html( safecss_filter_attr( "color: $link_color" ) );

$style = "<style>.$class_name a{" . $link_color_declaration . ";}</style>\n";

// Like the layout hook this assumes the hook only applies to blocks with a single wrapper.
// Retrieve the opening tag of the first HTML element.
$html_element_matches;
preg_match( '/<[^>]+>/', $block_content, $html_element_matches, PREG_OFFSET_CAPTURE );
$first_element = $html_element_matches[0][0];
// If the first HTML element has a class attribute just add the new class
// as we do on layout and duotone.
if ( strpos( $first_element, 'class="' ) !== false ) {
$content = preg_replace(
'/' . preg_quote( 'class="', '/' ) . '/',
'class="' . $class_name . ' ',
$block_content,
1
);
} else {
// If the first HTML element has no class attribute we should inject the attribute before the attribute at the end.
$first_element_offset = $html_element_matches[0][1];
$content = substr_replace( $block_content, ' class="' . $class_name . '"', $first_element_offset + strlen( $first_element ) - 1, 0 );
}
return $content . $style;

}


add_filter( 'render_block', 'gutenberg_render_elements_support', 10, 2 );
39 changes: 0 additions & 39 deletions lib/class-wp-theme-json.php
Original file line number Diff line number Diff line change
Expand Up @@ -1198,45 +1198,6 @@ private static function is_safe_css_declaration( $property_name, $property_value
return ! empty( trim( $filtered ) );
}

/**
* Whether the selector contains a link element.
*
* @param string $selector The selector to check.
*
* @return boolean
*/
private static function is_link_element( $selector ) {
if ( self::ELEMENTS['link'] === $selector ) {
return true;
}

$result = true;
if ( false === stripos( $selector, ' ' . self::ELEMENTS['link'] ) ) {
$result = false;
}

return $result;
}

/**
* Remove the link selector from the input.
*
* @param string $selector CSS selector to process.
*
* @return string
*/
private static function without_link_selector( $selector ) {
if ( self::ELEMENTS['link'] === $selector ) {
return $selector;
}

// The selector consist of "<something> <element_selector>".
// It can be compounded as well: "<one> <element_selector>, <two> <element_selector>, etc".
//
// We want to return "<something>" or "<one>, <two>, etc".
return str_ireplace( ' ' . self::ELEMENTS['link'], '', $selector );
}

/**
* Removes insecure data from theme.json.
*/
Expand Down
1 change: 1 addition & 0 deletions lib/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ function gutenberg_is_experiment_enabled( $name ) {
require __DIR__ . '/query-utils.php';

require __DIR__ . '/block-supports/generated-classname.php';
require __DIR__ . '/block-supports/elements.php';
require __DIR__ . '/block-supports/colors.php';
require __DIR__ . '/block-supports/align.php';
require __DIR__ . '/block-supports/typography.php';
Expand Down
32 changes: 17 additions & 15 deletions packages/block-editor/src/hooks/color.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* External dependencies
*/
import classnames from 'classnames';
import { isObject } from 'lodash';
import { isObject, setWith, clone } from 'lodash';

/**
* WordPress dependencies
Expand Down Expand Up @@ -205,6 +205,10 @@ const getLinkColorFromAttributeValue = ( colors, value ) => {
return value;
};

function immutableSet( object, path, value ) {
return setWith( object ? clone( object ) : {}, path, value, clone );
}

/**
* Inspector control panel containing the color related configuration
*
Expand Down Expand Up @@ -303,17 +307,15 @@ export function ColorEdit( props ) {

const onChangeLinkColor = ( value ) => {
const colorObject = getColorObjectByColorValue( colors, value );
props.setAttributes( {
style: {
...props.attributes.style,
color: {
...props.attributes.style?.color,
link: colorObject?.slug
? `var:preset|color|${ colorObject.slug }`
: value,
},
},
} );
const newLinkColorValue = colorObject?.slug
? `var:preset|color|${ colorObject.slug }`
: value;
const newStyle = immutableSet(
style,
[ 'elements', 'link', 'color', 'text' ],
newLinkColorValue
);
props.setAttributes( { style: newStyle } );
};

return (
Expand Down Expand Up @@ -363,10 +365,10 @@ export function ColorEdit( props ) {
onColorChange: onChangeLinkColor,
colorValue: getLinkColorFromAttributeValue(
colors,
style?.color?.link
style?.elements?.link?.color?.text
),
clearable: !! props.attributes.style?.color
?.link,
clearable: !! style?.elements?.link?.color
?.text,
},
]
: [] ),
Expand Down
92 changes: 89 additions & 3 deletions packages/block-editor/src/hooks/style.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
/**
* External dependencies
*/
import { capitalize, get, has, omit, omitBy, startsWith } from 'lodash';
import {
capitalize,
kebabCase,
get,
has,
map,
omit,
omitBy,
startsWith,
isEmpty,
first,
} from 'lodash';
import classnames from 'classnames';

/**
* WordPress dependencies
Expand All @@ -12,7 +24,7 @@ import {
hasBlockSupport,
__EXPERIMENTAL_STYLE_PROPERTY as STYLE_PROPERTY,
} from '@wordpress/blocks';
import { createHigherOrderComponent } from '@wordpress/compose';
import { createHigherOrderComponent, useInstanceId } from '@wordpress/compose';

/**
* Internal dependencies
Expand All @@ -31,6 +43,16 @@ const styleSupportKeys = [
SPACING_SUPPORT_KEY,
];

export const ELEMENTS = {
link: 'a',
h1: 'h1',
h2: 'h2',
h3: 'h3',
h4: 'h4',
h5: 'h5',
h6: 'h6',
};

const hasStyleSupport = ( blockType ) =>
styleSupportKeys.some( ( key ) => hasBlockSupport( blockType, key ) );

Expand Down Expand Up @@ -59,7 +81,8 @@ export function getInlineStyles( styles = {} ) {
Object.keys( STYLE_PROPERTY ).forEach( ( propKey ) => {
const path = STYLE_PROPERTY[ propKey ].value;
const subPaths = STYLE_PROPERTY[ propKey ].properties;
if ( has( styles, path ) ) {
// Ignore styles on elements because they are handled on the server.
if ( has( styles, path ) && 'elements' !== first( path ) ) {
if ( !! subPaths ) {
subPaths.forEach( ( suffix ) => {
output[
Expand All @@ -75,6 +98,24 @@ export function getInlineStyles( styles = {} ) {
return output;
}

function compileElementsStyles( selector, elements = {} ) {
return map( elements, ( styles, element ) => {
const elementStyles = getInlineStyles( styles );
if ( ! isEmpty( elementStyles ) ) {
return [
`.${ selector } ${ ELEMENTS[ element ] }{`,
...map(
elementStyles,
( value, property ) =>
`\t${ kebabCase( property ) }: ${ value }`
),
'}',
].join( '\n' );
}
return '';
} ).join( '\n' );
}

/**
* Filters registered block settings, extending attributes to include `style` attribute.
*
Expand Down Expand Up @@ -202,6 +243,45 @@ export const withBlockControls = createHigherOrderComponent(
'withToolbarControls'
);

/**
* Override the default block element to include duotone styles.
*
* @param {Function} BlockListBlock Original component
* @return {Function} Wrapped component
*/
const withElementsStyles = createHigherOrderComponent(
( BlockListBlock ) => ( props ) => {
const elements = props.attributes.style?.elements;
if ( ! elements ) {
return <BlockListBlock { ...props } />;
}
const blockElementsContainerIdentifier = `wp-block-elements-container-${ useInstanceId(
BlockListBlock
) }`;
const styles = compileElementsStyles(
blockElementsContainerIdentifier,
props.attributes.style?.elements
);

return (
<>
<style
dangerouslySetInnerHTML={ {
__html: styles,
} }
/>
<BlockListBlock
{ ...props }
className={ classnames(
props.classname,
blockElementsContainerIdentifier
) }
/>
</>
);
}
);

addFilter(
'blocks.registerBlockType',
'core/style/addAttribute',
Expand All @@ -225,3 +305,9 @@ addFilter(
'core/style/with-block-controls',
withBlockControls
);

addFilter(
'editor.BlockListBlock',
'core/editor/with-elements-styles',
withElementsStyles
);
4 changes: 4 additions & 0 deletions packages/blocks/src/api/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ export const __EXPERIMENTAL_STYLE_PROPERTY = {
value: [ 'color', 'text' ],
support: [ 'color' ],
},
linkColor: {
value: [ 'elements', 'link', 'color', 'text' ],
support: [ 'color', 'link' ],
},
fontFamily: {
value: [ 'typography', 'fontFamily' ],
support: [ '__experimentalFontFamily' ],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/
import {
capitalize,
first,
forEach,
get,
isEmpty,
Expand Down Expand Up @@ -118,6 +119,9 @@ function getStylesDeclarations( blockStyles = {} ) {
STYLE_PROPERTY,
( declarations, { value, properties }, key ) => {
const pathToValue = value;
if ( first( pathToValue ) === 'elements' ) {
return declarations;
}
if ( !! properties ) {
properties.forEach( ( prop ) => {
if (
Expand All @@ -127,9 +131,9 @@ function getStylesDeclarations( blockStyles = {} ) {
// for sub-properties that don't have any value.
return;
}
const cssProperty = key.startsWith( '--' )
? key
: kebabCase( `${ key }${ capitalize( prop ) }` );
const cssProperty = kebabCase(
`${ key }${ capitalize( prop ) }`
);
declarations.push(
`${ cssProperty }: ${ compileStyleValue(
get( blockStyles, [ ...pathToValue, prop ] )
Expand Down Expand Up @@ -275,12 +279,14 @@ export const toStyles = ( tree, blockSelectors ) => {
const nodesWithStyles = getNodesWithStyles( tree, blockSelectors );
const nodesWithSettings = getNodesWithSettings( tree, blockSelectors );

let ruleset = '';
nodesWithStyles.forEach( ( { selector, styles } ) => {
const declarations = getStylesDeclarations( styles );

if ( declarations.length === 0 ) {
return;
}
ruleset = ruleset + `${ selector }{${ declarations.join( ';' ) };}`;
} );

nodesWithSettings.forEach( ( { selector, presets } ) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ describe( 'global styles renderer', () => {
};

expect( toStyles( tree, blockSelectors ) ).toEqual(
'a{color: var(--wp--style--color--link, #00e);}body{background-color: red;}h1{font-size: 42px;}h1,h2,h3,h4,h5,h6{color: orange;}h1,h2,h3,h4,h5,h6{--wp--style--color--link: hotpink;}.has-white-color{color: white !important;}.has-white-background-color{background-color: white !important;}.has-white-border-color{border-color: white !important;}.has-black-color{color: black !important;}.has-black-background-color{background-color: black !important;}.has-black-border-color{border-color: black !important;}'
'body{background-color: red;}h1{font-size: 42px;}h1,h2,h3,h4,h5,h6{color: orange;}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{color: hotpink;}.has-white-color{color: white !important;}.has-white-background-color{background-color: white !important;}.has-white-border-color{border-color: white !important;}.has-black-color{color: black !important;}.has-black-background-color{background-color: black !important;}.has-black-border-color{border-color: black !important;}'
);
} );
} );
Expand Down
2 changes: 1 addition & 1 deletion packages/edit-site/src/components/editor/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ import { store as editSiteStore } from '../../store';
export const ROOT_BLOCK_NAME = 'root';
export const ROOT_BLOCK_SELECTOR = 'body';
export const ROOT_BLOCK_SUPPORTS = [
//'--wp--style--color--link',
'background',
'backgroundColor',
'color',
'linkColor',
'fontFamily',
'fontSize',
'fontStyle',
Expand Down

0 comments on commit 994e5e3

Please sign in to comment.