Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add block elements interactivity states #41383

Closed
wants to merge 10 commits into from
42 changes: 36 additions & 6 deletions lib/block-supports/elements.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ function gutenberg_get_elements_class_name( $block ) {
return 'wp-elements-' . md5( serialize( $block ) );
}



/**
* Update the block content with elements class names.
*
Expand All @@ -29,23 +31,29 @@ function gutenberg_render_elements_support( $block_content, $block ) {

$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] );
$skip_link_color_serialization = gutenberg_should_skip_block_supports_serialization( $block_type, 'color', 'link' );
$skip_link_hover_color_serialization = gutenberg_should_skip_block_supports_serialization( $block_type, 'color', 'link:hover' );

if ( $skip_link_color_serialization ) {
if ( $skip_link_color_serialization && $skip_link_hover_color_serialization ) {
return $block_content;
}

$link_color = null;
if ( ! empty( $block['attrs'] ) ) {
$link_color = _wp_array_get( $block['attrs'], array( 'style', 'elements', 'link', 'color', 'text' ), null );
}

$link_hover_color = null;
if ( ! empty( $block['attrs'] ) ) {
$link_hover_color = _wp_array_get( $block['attrs'], array( 'style', 'elements', 'link:hover', 'color', 'text' ), null );
}

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

Expand Down Expand Up @@ -75,7 +83,11 @@ function gutenberg_render_elements_support( $block_content, $block ) {
}

/**
* Render the elements stylesheet.
* Renders the elements stylesheet for a given block type.
*
* Each block may have styles for it's child HTML elements (currently only a limited subset are supported).
* Render an inline <style> block scoped to the block's CSS selector containing all the `element` style
* rules for the block.
*
* In the case of nested blocks we want the parent element styles to be rendered before their descendants.
* This solves the issue of an element (e.g.: link color) being styled in both the parent and a descendant:
Expand All @@ -90,15 +102,17 @@ function gutenberg_render_elements_support_styles( $pre_render, $block ) {
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] );
$element_block_styles = isset( $block['attrs']['style']['elements'] ) ? $block['attrs']['style']['elements'] : null;


/*
* For now we only care about link color.
* For now we only care about link color and link hover color.
* This code in the future when we have a public API
* should take advantage of WP_Theme_JSON_Gutenberg::compute_style_properties
* and work for any element and style.
*/
$skip_link_color_serialization = gutenberg_should_skip_block_supports_serialization( $block_type, 'color', 'link' );
$skip_link_hover_color_serialization = gutenberg_should_skip_block_supports_serialization( $block_type, 'color', 'link:hover' );

if ( $skip_link_color_serialization ) {
if ( $skip_link_color_serialization && $skip_link_hover_color_serialization) {
return null;
}
$class_name = gutenberg_get_elements_class_name( $block );
Expand All @@ -117,6 +131,22 @@ function gutenberg_render_elements_support_styles( $pre_render, $block ) {
gutenberg_enqueue_block_support_styles( $styles['css'] );
}
}

$link_hover_block_styles = isset( $element_block_styles['link:hover'] ) ? $element_block_styles['link:hover'] : null;

if ( $link_hover_block_styles ) {
$styles = gutenberg_style_engine_generate(
$link_hover_block_styles,
array(
'selector' => ".$class_name a:hover",
'css_vars' => true,
)
);

if ( ! empty( $styles['css'] ) ) {
gutenberg_enqueue_block_support_styles( $styles['css'] );
}
}

return null;
}
Expand Down
7 changes: 7 additions & 0 deletions lib/compat/wordpress-6.1/class-wp-theme-json-6-1.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,15 @@
class WP_Theme_JSON_6_1 extends WP_Theme_JSON_6_0 {
const __EXPERIMENTAL_ELEMENT_BUTTON_CLASS_NAME = 'wp-element-button';

/**
* The valid elements that can be found under styles.
*
* @since 5.8.0
* @var string[]
*/
const ELEMENTS = array(
'link' => 'a',
'link:hover' => 'a:hover',
'h1' => 'h1',
'h2' => 'h2',
'h3' => 'h3',
Expand Down
46 changes: 45 additions & 1 deletion packages/block-editor/src/hooks/color.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,13 @@ const resetAllLinkFilter = ( attributes ) => ( {
),
} );

const resetAllLinkHoverFilter = ( attributes ) => ( {
style: clearColorFromStyles(
[ 'elements', 'link:hover', 'color', 'text' ],
attributes.style
),
} );

/**
* Clears all background color related properties including gradients from
* supplied block attributes.
Expand Down Expand Up @@ -216,7 +223,6 @@ export function addSaveProps( props, blockType, attributes ) {
backgroundColor ||
style?.color?.background ||
( hasGradient && ( gradient || style?.color?.gradient ) );

const newClassName = classnames(
props.className,
textClass,
Expand All @@ -232,6 +238,9 @@ export function addSaveProps( props, blockType, attributes ) {
'has-background': serializeHasBackground && hasBackground,
'has-link-color':
shouldSerialize( 'link' ) && style?.elements?.link?.color,
'has-link-hover-color':
shouldSerialize( 'link:hover' ) &&
style?.elements?.[ 'link:hover' ]?.color,
}
);
props.className = newClassName ? newClassName : undefined;
Expand Down Expand Up @@ -284,6 +293,7 @@ const getLinkColorFromAttributeValue = ( colors, value ) => {
*/
export function ColorEdit( props ) {
const { name: blockName, attributes } = props;

// Some color settings have a special handling for deprecated flags in `useSetting`,
// so we can't unwrap them by doing const { ... } = useSetting('color')
// until https://github.com/WordPress/gutenberg/issues/37094 is fixed.
Expand Down Expand Up @@ -443,6 +453,26 @@ export function ColorEdit( props ) {
};
};

const onChangeLinkHoverColor = ( value ) => {
const colorObject = getColorObjectByColorValue( allSolids, value );
const newLinkColorValue = colorObject?.slug
? `var:preset|color|${ colorObject.slug }`
: value;

const newStyle = cleanEmptyObject(
immutableSet(
localAttributes.current?.style,
[ 'elements', 'link:hover', 'color', 'text' ],
newLinkColorValue
)
);
props.setAttributes( { style: newStyle } );
localAttributes.current = {
...localAttributes.current,
...{ style: newStyle },
};
};

const enableContrastChecking =
Platform.OS === 'web' && ! gradient && ! style?.color?.gradient;

Expand Down Expand Up @@ -508,6 +538,20 @@ export function ColorEdit( props ) {
isShownByDefault: defaultColorControls?.link,
resetAllFilter: resetAllLinkFilter,
},
{
label: __( 'Link Hover' ),
onColorChange: onChangeLinkHoverColor,
colorValue: getLinkColorFromAttributeValue(
allSolids,
style?.elements?.[ 'link:hover' ]?.color
?.text
),
clearable: !! style?.elements?.[ 'link:hover' ]
?.color?.text,
isShownByDefault:
defaultColorControls?.[ 'link:hover' ],
resetAllFilter: resetAllLinkHoverFilter,
},
]
: [] ),
] }
Expand Down
1 change: 1 addition & 0 deletions packages/blocks/src/api/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ export const __EXPERIMENTAL_STYLE_PROPERTY = {

export const __EXPERIMENTAL_ELEMENTS = {
link: 'a',
'link:hover': 'a:hover',
h1: 'h1',
h2: 'h2',
h3: 'h3',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
useStyle,
useColorsPerOrigin,
} from './hooks';
import Subtitle from './subtitle';

function ScreenLinkColor( { name } ) {
const supports = getSupportedGlobalStylesPanels( name );
Expand All @@ -39,6 +40,16 @@ function ScreenLinkColor( { name } ) {
'user'
);

const [ linkHoverColor, setLinkHoverColor ] = useStyle(
'elements.link:hover.color.text',
name
);
const [ userLinkHoverColor ] = useStyle(
'elements.link:hover.color.text',
name,
'user'
);

if ( ! hasLinkColor ) {
return null;
}
Expand All @@ -51,6 +62,7 @@ function ScreenLinkColor( { name } ) {
'Set the default color used for links across the site.'
) }
/>
<Subtitle>{ __( 'General' ) }</Subtitle>
<ColorGradientControl
className="edit-site-screen-link-color__control"
colors={ colorsPerOrigin }
Expand All @@ -63,6 +75,19 @@ function ScreenLinkColor( { name } ) {
onColorChange={ setLinkColor }
clearable={ linkColor === userLinkColor }
/>
<Subtitle>{ __( 'Hover' ) }</Subtitle>
<ColorGradientControl
className="edit-site-screen-link-color__control"
colors={ colorsPerOrigin }
disableCustomColors={ ! areCustomSolidsEnabled }
__experimentalHasMultipleOrigins
showTitle={ false }
enableAlpha
__experimentalIsRenderedInSidebar
colorValue={ linkHoverColor }
onColorChange={ setLinkHoverColor }
clearable={ linkColor === userLinkHoverColor }
/>
</>
);
}
Expand Down