diff --git a/lib/block-supports/duotone.php b/lib/block-supports/duotone.php index 5869d521b2d380..d2c64b68046972 100644 --- a/lib/block-supports/duotone.php +++ b/lib/block-supports/duotone.php @@ -251,64 +251,36 @@ function gutenberg_register_duotone_support( $block_type ) { } /** - * Render out the duotone stylesheet and SVG. + * Returns the markup for duotone style tag. * - * @param string $block_content Rendered block content. - * @param array $block Block object. - * @return string Filtered block content. + * @param string $selectors_group The selector to target. + * @param string $duotone_id The ID of the SVG filter. + * @return string The markup for the + tag. + */ +function gutenberg_get_duotone_svg_filters( $duotone_id, $duotone_values ) { + ob_start(); + ?> array(), + 'g' => array(), + 'b' => array(), + ); + foreach ( $duotone_colors as $color_str ) { + $color = gutenberg_tinycolor_string_to_rgb( $color_str ); + + $duotone_values['r'][] = $color['r'] / 255; + $duotone_values['g'][] = $color['g'] / 255; + $duotone_values['b'][] = $color['b'] / 255; + } + + return $duotone_values; +} + +/** + * Output Duotone markup in the footer. + * + * @param $duotone_markup The markup for the SVG filer, and if necessary the style tag. + */ +function gutenberg_output_duotone_markup( $duotone_markup ) { + add_action( + // Ideally we should use wp_head, but SVG defs can't be put in there. + is_admin() ? 'in_admin_footer' : 'wp_footer', + function () use ( $duotone_markup ) { + echo $duotone_markup; + } + ); +} + +/** + * Render out the duotone stylesheet and SVG. + * + * @param string $block_content Rendered block content. + * @param array $block Block object. + * @return string Filtered block content. + */ +function gutenberg_render_duotone_support( $block_content, $block ) { + $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); + + $duotone_support = false; + if ( $block_type && property_exists( $block_type, 'supports' ) ) { + $duotone_support = _wp_array_get( $block_type->supports, array( 'color', '__experimentalDuotone' ), false ); + } + + $has_duotone_attribute = isset( $block['attrs']['style']['color']['duotone'] ); + + if ( + ! $duotone_support || + ! $has_duotone_attribute + ) { + return $block_content; + } + + $duotone_colors = $block['attrs']['style']['color']['duotone']; + + $duotone_values = get_duotone_color_values( $duotone_colors ); + $duotone_id = gutenberg_get_duotone_filter_id( uniqid() ); + + $selectors = explode( ',', $duotone_support ); + $selectors_scoped = array_map( + function ( $selector ) use ( $duotone_id ) { + return '.' . $duotone_id . ' ' . trim( $selector ); + }, + $selectors + ); + $selectors_group = implode( ', ', $selectors_scoped ); + + if ( 'unset' === $duotone_colors ) { + $duotone_markup = ''; + } else { + $duotone_markup = gutenberg_get_duotone_style( $selectors_group, $duotone_id ); + $duotone_markup .= gutenberg_get_duotone_svg_filters( $duotone_id, $duotone_values ); + } - $duotone = ob_get_clean(); + if ( ! is_admin() ) { + gutenberg_output_duotone_markup( $duotone_markup ); + } // Like the layout hook, this assumes the hook only applies to blocks with a single wrapper. $content = preg_replace( @@ -351,14 +411,6 @@ function ( $selector ) use ( $duotone_id ) { 1 ); - add_action( - // Ideally we should use wp_head, but SVG defs can't be put in there. - 'wp_footer', - function () use ( $duotone ) { - echo $duotone; - } - ); - return $content; } @@ -373,3 +425,24 @@ function () use ( $duotone ) { // Remove WordPress core filter to avoid rendering duplicate support elements. remove_filter( 'render_block', 'wp_render_duotone_support', 10, 2 ); add_filter( 'render_block', 'gutenberg_render_duotone_support', 10, 2 ); + +/** + * Returns the ID for the duotone filter + * + * @param string $id The ID of the filter. + */ +function gutenberg_get_duotone_filter_id( $id ) { + return 'wp-duotone-' . $id; +} + +/** + * Generates duotone markup from a settings array + * + * @param array $duotone_setting Block object. + */ +function gutenberg_generate_duotone_filters_settings( $duotone_setting) { + $duotone_values = get_duotone_color_values( $duotone_setting['colors'] ); + $duotone_id = gutenberg_get_duotone_filter_id( $duotone_setting['slug'] ); + $duotone_markup = gutenberg_get_duotone_svg_filters( $duotone_id, $duotone_values ); + gutenberg_output_duotone_markup( $duotone_markup ); +} diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index cf713529b4f70d..772003aa1a863f 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -57,6 +57,7 @@ class WP_Theme_JSON_Gutenberg { ), 'color' => array( 'background' => null, + 'duotone' => null, 'gradient' => null, 'text' => null, ), @@ -218,6 +219,7 @@ class WP_Theme_JSON_Gutenberg { 'border-width' => array( 'border', 'width' ), 'border-style' => array( 'border', 'style' ), 'color' => array( 'color', 'text' ), + 'filter' => array( 'color', 'duotone' ), 'font-family' => array( 'typography', 'fontFamily' ), 'font-size' => array( 'typography', 'fontSize' ), 'font-style' => array( 'typography', 'fontStyle' ), @@ -855,6 +857,13 @@ private function get_block_styles( $style_nodes, $setting_nodes ) { $preset_rules .= self::compute_preset_classes( $node, $selector ); } + $theme_json_settings = $this->get_settings(); + if( ! empty( $theme_json_settings['color'] ) && ! empty( $theme_json_settings['color']['duotone'] ) && ! empty( $theme_json_settings['color']['duotone'] ) ) { + foreach( $theme_json_settings['color']['duotone'] as $duotone_setting ) { + gutenberg_generate_duotone_filters_settings( $duotone_setting ); + } + } + return $block_rules . $preset_rules; } diff --git a/lib/global-styles.php b/lib/global-styles.php index a749a66c40cf0d..59487ebf312c77 100644 --- a/lib/global-styles.php +++ b/lib/global-styles.php @@ -16,13 +16,13 @@ */ function gutenberg_experimental_global_styles_get_stylesheet( $tree, $type = 'all' ) { // Check if we can use cached. - $can_use_cached = ( + $can_use_cached = false; /*( ( 'all' === $type ) && ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) && ( ! defined( 'SCRIPT_DEBUG' ) || ! SCRIPT_DEBUG ) && ( ! defined( 'REST_REQUEST' ) || ! REST_REQUEST ) && ! is_admin() - ); + );*/ if ( $can_use_cached ) { // Check if we have the styles already cached. diff --git a/packages/block-editor/src/hooks/duotone.js b/packages/block-editor/src/hooks/duotone.js index 0bde4cdbe2c60e..031574a8f1319b 100644 --- a/packages/block-editor/src/hooks/duotone.js +++ b/packages/block-editor/src/hooks/duotone.js @@ -33,6 +33,10 @@ const EMPTY_ARRAY = []; * @return {Object} R, G, and B values. */ export function getValuesFromColors( colors = [] ) { + if ( typeof colors === 'string' ) { + return colors; + } + const values = { r: [], g: [], b: [] }; colors.forEach( ( color ) => { @@ -66,11 +70,21 @@ export function getValuesFromColors( colors = [] ) { * @return {WPElement} Duotone element. */ function DuotoneFilter( { selector, id, values } ) { + if ( values === 'unset' ) { + const unsetStylesheet = ` + ${ selector } { + filter: unset !important; /* We need !important to overide rules that come from theme.json.*/ + } + `; + return ( + + ); + } + const stylesheet = ` -${ selector } { - filter: url( #${ id } ); -} -`; + ${ selector } { + filter: url( #${ id } ) !important; /* We need !important to overide rules that come from theme.json.*/ + }`; return ( <> diff --git a/packages/block-library/src/image/block.json b/packages/block-library/src/image/block.json index 7aced7d40505e1..1d42c61932a548 100644 --- a/packages/block-library/src/image/block.json +++ b/packages/block-library/src/image/block.json @@ -84,7 +84,8 @@ }, "__experimentalBorder": { "radius": true - } + }, + "__experimentalSelector": ".wp-block-image img" }, "styles": [ { diff --git a/packages/components/src/duotone-picker/custom-duotone-bar.js b/packages/components/src/duotone-picker/custom-duotone-bar.js index 1a898273e392e7..c7bd30823b852f 100644 --- a/packages/components/src/duotone-picker/custom-duotone-bar.js +++ b/packages/components/src/duotone-picker/custom-duotone-bar.js @@ -12,10 +12,15 @@ import { const PLACEHOLDER_VALUES = [ '#333', '#CCC' ]; export default function CustomDuotoneBar( { value, onChange } ) { + if ( typeof value === 'string' ) { + return null; + } + const hasGradient = !! value; const values = hasGradient ? value : PLACEHOLDER_VALUES; const background = getGradientFromCSSColors( values ); const controlPoints = getColorStopsFromColors( values ); + return ( getDefaultColors( colorPalette ), [ colorPalette ] ); + const options = duotonePalette.map( ( { colors, slug, name } ) => { + const style = { + background: getGradientFromCSSColors( colors, '135deg' ), + color: 'transparent', + }; + const tooltipText = + name ?? + sprintf( + // translators: %s: duotone code e.g: "dark-grayscale" or "7f7f7f-ffffff". + __( 'Duotone code: %s' ), + slug + ); + const label = name + ? sprintf( + // translators: %s: The name of the option e.g: "Dark grayscale". + __( 'Duotone: %s' ), + name + ) + : tooltipText; + const isSelected = isEqual( colors, value ); + + return ( + { + onChange( isSelected ? undefined : colors ); + } } + /> + ); + } ); + + // Add a disable duotone option. + const disableOption = ( + " )', + color: 'transparent', + } } + onClick={ () => { + onChange( value === 'unset' ? undefined : 'unset' ); + } } + /> + ); return ( { - const style = { - background: getGradientFromCSSColors( colors, '135deg' ), - color: 'transparent', - }; - const tooltipText = - name ?? - sprintf( - // translators: %s: duotone code e.g: "dark-grayscale" or "7f7f7f-ffffff". - __( 'Duotone code: %s' ), - slug - ); - const label = name - ? sprintf( - // translators: %s: The name of the option e.g: "Dark grayscale". - __( 'Duotone: %s' ), - name - ) - : tooltipText; - const isSelected = isEqual( colors, value ); - - return ( - { - onChange( isSelected ? undefined : colors ); - } } - /> - ); - } ) } + options={ [ disableOption, ...options ] } actions={ - onChange( undefined ) } - > - { __( 'Clear' ) } - +
+ onChange( undefined ) } + > + { __( 'Clear' ) } + +
} > { ! disableCustomColors && ! disableCustomDuotone && ( diff --git a/packages/components/src/duotone-picker/duotone-swatch.js b/packages/components/src/duotone-picker/duotone-swatch.js index 1ab35b53034c7d..7e89ef2cc58172 100644 --- a/packages/components/src/duotone-picker/duotone-swatch.js +++ b/packages/components/src/duotone-picker/duotone-swatch.js @@ -6,6 +6,10 @@ import Swatch from '../swatch'; import { getGradientFromCSSColors } from './utils'; function DuotoneSwatch( { values } ) { + if ( typeof values === 'string' ) { + return ; + } + return ( ( { position: ( i * 100 ) / ( colors.length - 1 ), color,