Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 12 additions & 25 deletions blocks/duotone-filter/duotone.php
Original file line number Diff line number Diff line change
@@ -1,52 +1,39 @@
<?php

if ( ! function_exists( 'hex2rgb' ) ) {
function hex2rgb( $color ) {
if ( strlen( $color ) === 4 ) {
$r = hexdec( substr( $color, 1, 1 ) . substr( $color, 1, 1 ) );
$g = hexdec( substr( $color, 2, 1 ) . substr( $color, 2, 1 ) );
$b = hexdec( substr( $color, 3, 1 ) . substr( $color, 3, 1 ) );
} elseif ( strlen( $color ) === 7 ) {
$r = hexdec( substr( $color, 1, 2 ) );
$g = hexdec( substr( $color, 3, 2 ) );
$b = hexdec( substr( $color, 5, 2 ) );
} else {
return array();
}

return array(
'r' => $r / 0xff,
'g' => $g / 0xff,
'b' => $b / 0xff,
);
}
}
include_once 'utils.php';

// phpcs:disable
$duotone_id = $block['attrs']['duotoneId'];
$duotone_selector = '.wp-block-image.' . $duotone_id . ' img';
$duotone_dark = hex2rgb( $block['attrs']['duotoneDark'] );
$duotone_light = hex2rgb( $block['attrs']['duotoneLight'] );
// phpcs:enable

?>

<style>
<?php echo $duotone_selector; ?> {
filter: url( <?php echo '#' . $duotone_id; ?> );
}
</style>

<svg
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 0 0"
width="0"
height="0"
focusable="false"
role="none"
style="visibility: hidden !important; position: absolute !important; left: -9999px !important; overflow: hidden !important;"
style="visibility: hidden; position: absolute; left: -9999px; overflow: hidden;"
>
<defs>
<filter id="<?php echo $duotone_id; ?>">
<feColorMatrix
type="matrix"
<?php // phpcs:disable ?>
values=".2989 .5870 .1140 0 0
.2989 .5870 .1140 0 0
.2989 .5870 .1140 0 0
values=".299 .587 .114 0 0
.299 .587 .114 0 0
.299 .587 .114 0 0
0 0 0 1 0"
<?php // phpcs:enable ?>
/>
Expand Down
10 changes: 5 additions & 5 deletions blocks/duotone-filter/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@
] );

function is_supported_block( $block ) {
$supported_blocks = [ 'core/image', 'core/cover' ];
$supported_blocks = [ 'core/image' ];
return in_array( $block['blockName'], $supported_blocks, true );
}

add_filter( 'render_block', function ( $block_content, $block ) {
if (
! is_supported_block( $block ) ||
! array_key_exists( 'duotoneId', $block['attrs'] ) ||
! array_key_exists( 'duotoneDark', $block['attrs'] ) ||
! array_key_exists( 'duotoneLight', $block['attrs'] )
! isset( $block['attrs']['duotoneId'] ) ||
! isset( $block['attrs']['duotoneDark'] ) ||
! isset( $block['attrs']['duotoneLight'] )
) {
return $block_content;
}
Expand All @@ -26,6 +26,6 @@ function is_supported_block( $block ) {
include 'duotone.php';
$duotone = ob_get_clean();

return $duotone . $block_content;
return $block_content . $duotone;
}, 10, 2 );
} );
118 changes: 54 additions & 64 deletions blocks/duotone-filter/src/duotone.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,76 +3,66 @@
*/
import { SVG } from '@wordpress/components';

const hex2rgb = ( color = '' ) => {
let r = '0';
let g = '0';
let b = '0';

if ( color.length === 4 ) {
r = '0x' + color[ 1 ] + color[ 1 ];
g = '0x' + color[ 2 ] + color[ 2 ];
b = '0x' + color[ 3 ] + color[ 3 ];
} else if ( color.length === 7 ) {
r = '0x' + color[ 1 ] + color[ 2 ];
g = '0x' + color[ 3 ] + color[ 4 ];
b = '0x' + color[ 5 ] + color[ 6 ];
} else {
return {};
}

return {
r: r / 0xff,
g: g / 0xff,
b: b / 0xff,
};
};
/**
* Internal dependencies
*/
import { hex2rgb } from './utils';

function Duotone( { id: duotoneId, darkColor, lightColor } ) {
function Duotone( { id: duotoneId, darkColor, lightColor, selector } ) {
const duotoneDark = hex2rgb( darkColor );
const duotoneLight = hex2rgb( lightColor );

const stylesheet = `
${ selector } {
filter: url( #${ duotoneId } );
}
`;

return (
<SVG
xmlnsXlink="http://www.w3.org/1999/xlink"
viewBox="0 0 0 0"
width="0"
height="0"
focusable="false"
role="none"
style={ {
visibility: 'hidden',
position: 'absolute',
left: '-9999px',
overflow: 'hidden',
} }
>
<defs>
<filter id={ duotoneId }>
<feColorMatrix
type="matrix"
// prettier-ignore
values=".2989 .5870 .1140 0 0
.2989 .5870 .1140 0 0
.2989 .5870 .1140 0 0
0 0 0 1 0"
/>
<feComponentTransfer colorInterpolationFilters="sRGB">
<feFuncR
type="table"
tableValues={ `${ duotoneDark.r } ${ duotoneLight.r }` }
/>
<feFuncG
type="table"
tableValues={ `${ duotoneDark.g } ${ duotoneLight.g }` }
/>
<feFuncB
type="table"
tableValues={ `${ duotoneDark.b } ${ duotoneLight.b }` }
<>
<SVG
xmlnsXlink="http://www.w3.org/1999/xlink"
viewBox="0 0 0 0"
width="0"
height="0"
focusable="false"
role="none"
style={ {
visibility: 'hidden',
position: 'absolute',
left: '-9999px',
overflow: 'hidden',
} }
>
<defs>
<filter id={ duotoneId }>
<feColorMatrix
type="matrix"
// prettier-ignore
values=".299 .587 .114 0 0
.299 .587 .114 0 0
.299 .587 .114 0 0
0 0 0 1 0"
/>
</feComponentTransfer>
</filter>
</defs>
</SVG>
<feComponentTransfer colorInterpolationFilters="sRGB">
<feFuncR
type="table"
tableValues={ `${ duotoneDark.r } ${ duotoneLight.r }` }
/>
<feFuncG
type="table"
tableValues={ `${ duotoneDark.g } ${ duotoneLight.g }` }
/>
<feFuncB
type="table"
tableValues={ `${ duotoneDark.b } ${ duotoneLight.b }` }
/>
</feComponentTransfer>
</filter>
</defs>
</SVG>
<style dangerouslySetInnerHTML={ { __html: stylesheet } } />
</>
);
}

Expand Down
111 changes: 85 additions & 26 deletions blocks/duotone-filter/src/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
/**
* External dependencies
*/
import classnames from 'classnames';

/**
* WordPress dependencies
*/
import { InspectorControls, PanelColorSettings } from '@wordpress/block-editor';
import { createHigherOrderComponent, useInstanceId } from '@wordpress/compose';
import { useSelect } from '@wordpress/data';
import { useEffect } from '@wordpress/element';
import { addFilter } from '@wordpress/hooks';
import { __ } from '@wordpress/i18n';
Expand All @@ -11,8 +17,12 @@ import { __ } from '@wordpress/i18n';
* Internal dependencies
*/
import Duotone from './duotone';
import { hex2rgb } from './utils';

const SUPPORTED_BLOCKS = [ 'core/image', 'core/cover' ];
const FALLBACK_DARK_COLOR = '#000';
const FALLBACK_LIGHT_COLOR = '#fff';

const SUPPORTED_BLOCKS = [ 'core/image' ];

export const isSupportedBlock = ( blockName ) =>
SUPPORTED_BLOCKS.includes( blockName );
Expand All @@ -34,9 +44,20 @@ const withDuotoneAttributes = ( settings, blockName ) => {
return settings;
};

/**
* Convert a hex color to perceived brightness.
*
* @param {string} color Hex color
* @return {number} Perceived brightness of the color
*/
const toBrightness = ( color ) => {
const { r, g, b } = hex2rgb( color );
return r * 0.299 + g * 0.587 + b * 0.114;
};

const withDuotoneEditorControls = createHigherOrderComponent(
( BlockEdit ) => ( props ) => {
const { name: blockName, attributes, setAttributes } = props;
const { name: blockName, attributes, setAttributes, clientId } = props;

if ( ! isSupportedBlock( blockName ) ) {
return <BlockEdit { ...props } />;
Expand All @@ -50,6 +71,29 @@ const withDuotoneEditorControls = createHigherOrderComponent(
} );
}, [ instanceId ] );

const [
defaultDarkColor = FALLBACK_DARK_COLOR,
defaultLightColor = FALLBACK_LIGHT_COLOR,
] = useSelect( ( select ) => {
const { colors } = select( 'core/block-editor' ).getSettings();
return colors
.map( ( { color } ) => ( {
color,
brightness: toBrightness( color ),
} ) )
.reduce( ( [ min, max ], current ) => {
return [
! min || current.brightness < min.brightness
? current
: min,
! max || current.brightness > max.brightness
? current
: max,
];
}, [] )
.map( ( { color } ) => color );
}, [] );

return (
<>
<InspectorControls>
Expand All @@ -60,38 +104,55 @@ const withDuotoneEditorControls = createHigherOrderComponent(
{
label: __( 'Dark Color', 'block-experiments' ),
value: attributes.duotoneDark,
onChange: ( duotoneDark ) =>
setAttributes( { duotoneDark } ),
onChange: ( duotoneDark ) => {
if (
duotoneDark &&
! attributes.duotoneLight
) {
setAttributes( {
duotoneLight:
duotoneDark !==
defaultLightColor
? defaultLightColor
: FALLBACK_LIGHT_COLOR,
} );
}
setAttributes( { duotoneDark } );
},
},
{
label: __( 'Light Color', 'block-experiments' ),
value: attributes.duotoneLight,
onChange: ( duotoneLight ) =>
setAttributes( { duotoneLight } ),
onChange: ( duotoneLight ) => {
if (
duotoneLight &&
! attributes.duotoneDark
) {
setAttributes( {
duotoneDark:
duotoneLight !==
defaultDarkColor
? defaultDarkColor
: FALLBACK_DARK_COLOR,
} );
}
setAttributes( { duotoneLight } );
},
},
] }
/>
</InspectorControls>
<BlockEdit { ...props } />
{ attributes.duotoneDark &&
attributes.duotoneLight &&
attributes.duotoneId ? (
<>
<Duotone
id={ attributes.duotoneId }
darkColor={ attributes.duotoneDark }
lightColor={ attributes.duotoneLight }
/>
<div
style={ {
filter: `url( #${ attributes.duotoneId } )`,
} }
>
<BlockEdit { ...props } />
</div>
</>
) : (
<BlockEdit { ...props } />
) }
<Duotone
selector={ `#block-${ clientId } img` }
id={ attributes.duotoneId }
darkColor={ attributes.duotoneDark }
lightColor={ attributes.duotoneLight }
/>
) : null }
</>
);
},
Expand All @@ -108,9 +169,7 @@ function addDuotoneFilterStyle( props, block, attributes ) {
return props;
}

const { style = {} } = props;

return { style: { ...style, filter: `url( #${ attributes.duotoneId } )` } };
return { className: classnames( props.className, attributes.duotoneId ) };
}

export function registerBlock() {
Expand Down
Loading