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

Enable transparency for duotone #34130

Merged
merged 14 commits into from Oct 29, 2021
62 changes: 53 additions & 9 deletions lib/block-supports/duotone.php
Expand Up @@ -36,6 +36,25 @@ function gutenberg_tinycolor_bound01( $n, $max ) {
return ( $n % $max ) / (float) $max;
}

/**
* Direct port of tinycolor's boundAlpha function to maintain consistency with
* how tinycolor works.
*
* @see https://github.com/bgrins/TinyColor
*
* @param mixed $n Number of unknown type.
* @return float Value in the range [0,1].
*/
function gutenberg_tinycolor_bound_alpha( $n ) {
if ( is_numeric( $n ) ) {
$n = (float) $n;
if ( $n >= 0 && $n <= 1 ) {
return $n;
}
}
return 1;
}

/**
* Round and convert values of an RGB object.
*
Expand Down Expand Up @@ -138,90 +157,112 @@ function gutenberg_tinycolor_string_to_rgb( $color_str ) {

$rgb_regexp = '/^rgb' . $permissive_match3 . '$/';
if ( preg_match( $rgb_regexp, $color_str, $match ) ) {
return gutenberg_tinycolor_rgb_to_rgb(
$rgb = gutenberg_tinycolor_rgb_to_rgb(
array(
'r' => $match[1],
'g' => $match[2],
'b' => $match[3],
)
);
$rgb['a'] = 1;
return $rgb;
}

$rgba_regexp = '/^rgba' . $permissive_match4 . '$/';
if ( preg_match( $rgba_regexp, $color_str, $match ) ) {
return gutenberg_tinycolor_rgb_to_rgb(
$rgb = gutenberg_tinycolor_rgb_to_rgb(
array(
'r' => $match[1],
'g' => $match[2],
'b' => $match[3],
)
);
$rgb['a'] = gutenberg_tinycolor_bound_alpha( $match[4] );
return $rgb;
}

$hsl_regexp = '/^hsl' . $permissive_match3 . '$/';
if ( preg_match( $hsl_regexp, $color_str, $match ) ) {
return gutenberg_tinycolor_hsl_to_rgb(
$rgb = gutenberg_tinycolor_hsl_to_rgb(
array(
'h' => $match[1],
's' => $match[2],
'l' => $match[3],
)
);
$rgb['a'] = 1;
return $rgb;
}

$hsla_regexp = '/^hsla' . $permissive_match4 . '$/';
if ( preg_match( $hsla_regexp, $color_str, $match ) ) {
return gutenberg_tinycolor_hsl_to_rgb(
$rgb = gutenberg_tinycolor_hsl_to_rgb(
array(
'h' => $match[1],
's' => $match[2],
'l' => $match[3],
'a' => $match[4],
)
);
$rgb['a'] = gutenberg_tinycolor_bound_alpha( $match[4] );
return $rgb;
}

$hex8_regexp = '/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/';
if ( preg_match( $hex8_regexp, $color_str, $match ) ) {
return gutenberg_tinycolor_rgb_to_rgb(
$rgb = gutenberg_tinycolor_rgb_to_rgb(
array(
'r' => base_convert( $match[1], 16, 10 ),
'g' => base_convert( $match[2], 16, 10 ),
'b' => base_convert( $match[3], 16, 10 ),
)
);
$rgb['a'] = gutenberg_tinycolor_bound_alpha(
base_convert( $match[4], 16, 10 ) / 255
);
return $rgb;
}

$hex6_regexp = '/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/';
if ( preg_match( $hex6_regexp, $color_str, $match ) ) {
return gutenberg_tinycolor_rgb_to_rgb(
$rgb = gutenberg_tinycolor_rgb_to_rgb(
array(
'r' => base_convert( $match[1], 16, 10 ),
'g' => base_convert( $match[2], 16, 10 ),
'b' => base_convert( $match[3], 16, 10 ),
'a' => 1,
)
);
$rgb['a'] = 1;
return $rgb;
}

$hex4_regexp = '/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/';
if ( preg_match( $hex4_regexp, $color_str, $match ) ) {
return gutenberg_tinycolor_rgb_to_rgb(
$rgb = gutenberg_tinycolor_rgb_to_rgb(
array(
'r' => base_convert( $match[1] . $match[1], 16, 10 ),
'g' => base_convert( $match[2] . $match[2], 16, 10 ),
'b' => base_convert( $match[3] . $match[3], 16, 10 ),
)
);
$rgb['a'] = gutenberg_tinycolor_bound_alpha(
base_convert( $match[4] . $match[4], 16, 10 ) / 255
);
return $rgb;
}

$hex3_regexp = '/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/';
if ( preg_match( $hex3_regexp, $color_str, $match ) ) {
return gutenberg_tinycolor_rgb_to_rgb(
$rgb = gutenberg_tinycolor_rgb_to_rgb(
array(
'r' => base_convert( $match[1] . $match[1], 16, 10 ),
'g' => base_convert( $match[2] . $match[2], 16, 10 ),
'b' => base_convert( $match[3] . $match[3], 16, 10 ),
)
);
$rgb['a'] = 1;
return $rgb;
}
}

Expand Down Expand Up @@ -280,13 +321,15 @@ function gutenberg_render_duotone_support( $block_content, $block ) {
'r' => array(),
'g' => array(),
'b' => array(),
'a' => 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;
$duotone_values['a'][] = $color['a'];
}

$duotone_id = 'wp-duotone-filter-' . uniqid();
Expand Down Expand Up @@ -327,13 +370,14 @@ function ( $selector ) use ( $duotone_id ) {
values=".299 .587 .114 0 0
.299 .587 .114 0 0
.299 .587 .114 0 0
0 0 0 1 0"
.299 .587 .114 0 0"
<?php // phpcs:enable Generic.WhiteSpace.DisallowSpaceIndent ?>
/>
<feComponentTransfer color-interpolation-filters="sRGB" >
<feFuncR type="table" tableValues="<?php echo esc_attr( implode( ' ', $duotone_values['r'] ) ); ?>" />
<feFuncG type="table" tableValues="<?php echo esc_attr( implode( ' ', $duotone_values['g'] ) ); ?>" />
<feFuncB type="table" tableValues="<?php echo esc_attr( implode( ' ', $duotone_values['b'] ) ); ?>" />
<feFuncA type="table" tableValues="<?php echo esc_attr( implode( ' ', $duotone_values['a'] ) ); ?>" />
</feComponentTransfer>
</filter>
</defs>
Expand Down
12 changes: 9 additions & 3 deletions packages/block-editor/src/hooks/duotone.js
Expand Up @@ -33,14 +33,15 @@ const EMPTY_ARRAY = [];
* @return {Object} R, G, and B values.
*/
export function getValuesFromColors( colors = [] ) {
const values = { r: [], g: [], b: [] };
const values = { r: [], g: [], b: [], a: [] };

colors.forEach( ( color ) => {
// Access values directly to skip extra rounding that tinycolor.toRgb() does.
const tcolor = tinycolor( color );
values.r.push( tcolor._r / 255 );
values.g.push( tcolor._g / 255 );
values.b.push( tcolor._b / 255 );
values.a.push( tcolor._a );
} );

return values;
Expand All @@ -53,6 +54,7 @@ export function getValuesFromColors( colors = [] ) {
* @property {number[]} r Red values.
* @property {number[]} g Green values.
* @property {number[]} b Blue values.
* @property {number[]} a Alpha values.
*/

/**
Expand All @@ -61,7 +63,7 @@ export function getValuesFromColors( colors = [] ) {
* @param {Object} props Duotone props.
* @param {string} props.selector Selector to apply the filter to.
* @param {string} props.id Unique id for this duotone filter.
* @param {Values} props.values R, G, and B values to filter with.
* @param {Values} props.values R, G, B, and A values to filter with.
*
* @return {WPElement} Duotone element.
*/
Expand Down Expand Up @@ -97,7 +99,7 @@ ${ selector } {
values=".299 .587 .114 0 0
.299 .587 .114 0 0
.299 .587 .114 0 0
0 0 0 1 0"
.299 .587 .114 0 0"
ajlende marked this conversation as resolved.
Show resolved Hide resolved
/>
<feComponentTransfer
// Use sRGB instead of linearRGB to be consistent with how CSS gradients work.
Expand All @@ -115,6 +117,10 @@ ${ selector } {
type="table"
tableValues={ values.b.join( ' ' ) }
/>
<feFuncA
type="table"
tableValues={ values.a.join( ' ' ) }
/>
</feComponentTransfer>
</filter>
</defs>
Expand Down
4 changes: 4 additions & 0 deletions packages/components/src/color-list-picker/index.js
Expand Up @@ -15,6 +15,7 @@ function ColorOption( {
value,
colors,
disableCustomColors,
disableAlpha,
onChange,
} ) {
const [ isOpen, setIsOpen ] = useState( false );
Expand All @@ -34,6 +35,7 @@ function ColorOption( {
clearable={ false }
onChange={ onChange }
disableCustomColors={ disableCustomColors }
disableAlpha={ disableAlpha }
/>
) }
</>
Expand All @@ -45,6 +47,7 @@ function ColorListPicker( {
labels,
value = [],
disableCustomColors,
disableAlpha,
onChange,
} ) {
return (
Expand All @@ -56,6 +59,7 @@ function ColorListPicker( {
value={ value[ index ] }
colors={ colors }
disableCustomColors={ disableCustomColors }
disableAlpha={ disableAlpha }
onChange={ ( newColor ) => {
const newColors = value.slice();
newColors[ index ] = newColor;
Expand Down
3 changes: 2 additions & 1 deletion packages/components/src/color-palette/index.js
Expand Up @@ -21,6 +21,7 @@ export default function ColorPalette( {
className,
colors,
disableCustomColors = false,
disableAlpha = true,
onChange,
value,
} ) {
Expand Down Expand Up @@ -62,7 +63,7 @@ export default function ColorPalette( {
<ColorPicker
color={ value }
onChangeComplete={ ( color ) => onChange( color.hex ) }
disableAlpha
disableAlpha={ disableAlpha }
/>
);

Expand Down
Expand Up @@ -19,7 +19,6 @@ export default function CustomDuotoneBar( { value, onChange } ) {
return (
<CustomGradientBar
disableInserter
disableAlpha
background={ background }
hasGradient={ hasGradient }
value={ controlPoints }
Expand Down
1 change: 1 addition & 0 deletions packages/components/src/duotone-picker/duotone-picker.js
Expand Up @@ -85,6 +85,7 @@ function DuotonePicker( {
colors={ colorPalette }
value={ value }
disableCustomColors={ disableCustomColors }
disableAlpha={ false }
onChange={ ( newColors ) => {
if ( ! newColors[ 0 ] ) {
newColors[ 0 ] = defaultDark;
Expand Down