diff --git a/packages/block-editor/src/components/block-preview/auto.js b/packages/block-editor/src/components/block-preview/auto.js
index 933758f7eb76f5..5a78e7abeb3b4c 100644
--- a/packages/block-editor/src/components/block-preview/auto.js
+++ b/packages/block-editor/src/components/block-preview/auto.js
@@ -12,6 +12,7 @@ import { useMemo } from '@wordpress/element';
import BlockList from '../block-list';
import Iframe from '../iframe';
import EditorStyles from '../editor-styles';
+import { __unstablePresetDuotoneFilter as PresetDuotoneFilter } from '../../components/duotone';
import { store } from '../../store';
// This is used to avoid rendering the block list if the sizes change.
@@ -28,11 +29,12 @@ function AutoBlockPreview( {
useResizeObserver();
const [ contentResizeListener, { height: contentHeight } ] =
useResizeObserver();
- const { styles, assets } = useSelect( ( select ) => {
+ const { styles, assets, duotone } = useSelect( ( select ) => {
const settings = select( store ).getSettings();
return {
styles: settings.styles,
assets: settings.__unstableResolvedAssets,
+ duotone: settings.__experimentalFeatures?.color?.duotone,
};
}, [] );
@@ -51,11 +53,14 @@ function AutoBlockPreview( {
return styles;
}, [ styles ] );
+ const svgFilters = useMemo( () => {
+ return [ ...( duotone?.default ?? [] ), ...( duotone?.theme ?? [] ) ];
+ }, [ duotone ] );
+
// Initialize on render instead of module top level, to avoid circular dependency issues.
MemoizedBlockList = MemoizedBlockList || pure( BlockList );
const scale = containerWidth / viewportWidth;
-
return (
{ containerResizeListener }
@@ -106,6 +111,15 @@ function AutoBlockPreview( {
} }
>
{ contentResizeListener }
+ {
+ /* Filters need to be rendered before children to avoid Safari rendering issues. */
+ svgFilters.map( ( preset ) => (
+
+ ) )
+ }
diff --git a/packages/block-editor/src/components/duotone/components.js b/packages/block-editor/src/components/duotone/components.js
new file mode 100644
index 00000000000000..2ec019849a02a3
--- /dev/null
+++ b/packages/block-editor/src/components/duotone/components.js
@@ -0,0 +1,133 @@
+/**
+ * WordPress dependencies
+ */
+import { SVG } from '@wordpress/components';
+
+/**
+ * Internal dependencies
+ */
+import { __unstableGetValuesFromColors as getValuesFromColors } from './index';
+
+/**
+ * SVG and stylesheet needed for rendering the duotone filter.
+ *
+ * @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.
+ *
+ * @return {WPElement} Duotone element.
+ */
+export function DuotoneStylesheet( { selector, id } ) {
+ const css = `
+${ selector } {
+ filter: url( #${ id } );
+}
+`;
+ return ;
+}
+
+/**
+ * Stylesheet for disabling a global styles duotone filter.
+ *
+ * @param {Object} props Duotone props.
+ * @param {string} props.selector Selector to disable the filter for.
+ *
+ * @return {WPElement} Filter none style element.
+ */
+export function DuotoneUnsetStylesheet( { selector } ) {
+ const css = `
+${ selector } {
+ filter: none;
+}
+`;
+ return ;
+}
+
+/**
+ * The SVG part of the duotone filter.
+ *
+ * @param {Object} props Duotone props.
+ * @param {string} props.id Unique id for this duotone filter.
+ * @param {string[]} props.colors Color strings from dark to light.
+ *
+ * @return {WPElement} Duotone SVG.
+ */
+export function DuotoneFilter( { id, colors } ) {
+ const values = getValuesFromColors( colors );
+ return (
+
+ );
+}
+
+/**
+ * SVG from a duotone preset
+ *
+ * @param {Object} props Duotone props.
+ * @param {Object} props.preset Duotone preset settings.
+ *
+ * @return {WPElement} Duotone element.
+ */
+export function PresetDuotoneFilter( { preset } ) {
+ return (
+
+ );
+}
diff --git a/packages/block-editor/src/components/duotone/index.js b/packages/block-editor/src/components/duotone/index.js
new file mode 100644
index 00000000000000..919d67780d7c7d
--- /dev/null
+++ b/packages/block-editor/src/components/duotone/index.js
@@ -0,0 +1,7 @@
+export { getValuesFromColors as __unstableGetValuesFromColors } from './utils';
+export {
+ DuotoneFilter as __unstableDuotoneFilter,
+ PresetDuotoneFilter as __unstablePresetDuotoneFilter,
+ DuotoneStylesheet as __unstableDuotoneStylesheet,
+ DuotoneUnsetStylesheet as __unstableDuotoneUnsetStylesheet,
+} from './components';
diff --git a/packages/block-editor/src/components/duotone/utils.js b/packages/block-editor/src/components/duotone/utils.js
new file mode 100644
index 00000000000000..d7cbd0ccba26e9
--- /dev/null
+++ b/packages/block-editor/src/components/duotone/utils.js
@@ -0,0 +1,25 @@
+/**
+ * External dependencies
+ */
+import { colord } from 'colord';
+
+/**
+ * Convert a list of colors to an object of R, G, and B values.
+ *
+ * @param {string[]} colors Array of RBG color strings.
+ *
+ * @return {Object} R, G, and B values.
+ */
+export function getValuesFromColors( colors = [] ) {
+ const values = { r: [], g: [], b: [], a: [] };
+
+ colors.forEach( ( color ) => {
+ const rgbColor = colord( color ).toRgb();
+ values.r.push( rgbColor.r / 255 );
+ values.g.push( rgbColor.g / 255 );
+ values.b.push( rgbColor.b / 255 );
+ values.a.push( rgbColor.a );
+ } );
+
+ return values;
+}
diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js
index 0dec53f9579528..cf1967e429cbf5 100644
--- a/packages/block-editor/src/components/index.js
+++ b/packages/block-editor/src/components/index.js
@@ -5,6 +5,7 @@
export * from './colors';
export * from './gradients';
export * from './font-sizes';
+export * from './duotone';
export { AlignmentControl, AlignmentToolbar } from './alignment-control';
export { default as Autocomplete } from './autocomplete';
export {
diff --git a/packages/block-editor/src/hooks/duotone.js b/packages/block-editor/src/hooks/duotone.js
index afcf3b4d27f914..5cc610ae1047b3 100644
--- a/packages/block-editor/src/hooks/duotone.js
+++ b/packages/block-editor/src/hooks/duotone.js
@@ -2,14 +2,13 @@
* External dependencies
*/
import classnames from 'classnames';
-import { colord, extend } from 'colord';
+import { extend } from 'colord';
import namesPlugin from 'colord/plugins/names';
/**
* WordPress dependencies
*/
import { getBlockSupport, hasBlockSupport } from '@wordpress/blocks';
-import { SVG } from '@wordpress/components';
import { createHigherOrderComponent, useInstanceId } from '@wordpress/compose';
import { addFilter } from '@wordpress/hooks';
import { useMemo, useContext, createPortal } from '@wordpress/element';
@@ -23,139 +22,16 @@ import {
useSetting,
} from '../components';
import BlockList from '../components/block-list';
+import {
+ __unstableDuotoneFilter as DuotoneFilter,
+ __unstableDuotoneStylesheet as DuotoneStylesheet,
+ __unstableDuotoneUnsetStylesheet as DuotoneUnsetStylesheet,
+} from '../components/duotone';
const EMPTY_ARRAY = [];
extend( [ namesPlugin ] );
-/**
- * Convert a list of colors to an object of R, G, and B values.
- *
- * @param {string[]} colors Array of RBG color strings.
- *
- * @return {Object} R, G, and B values.
- */
-export function getValuesFromColors( colors = [] ) {
- const values = { r: [], g: [], b: [], a: [] };
-
- colors.forEach( ( color ) => {
- const rgbColor = colord( color ).toRgb();
- values.r.push( rgbColor.r / 255 );
- values.g.push( rgbColor.g / 255 );
- values.b.push( rgbColor.b / 255 );
- values.a.push( rgbColor.a );
- } );
-
- return values;
-}
-
-/**
- * SVG and stylesheet needed for rendering the duotone filter.
- *
- * @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.
- *
- * @return {WPElement} Duotone element.
- */
-function DuotoneStylesheet( { selector, id } ) {
- const css = `
-${ selector } {
- filter: url( #${ id } );
-}
-`;
- return ;
-}
-
-/**
- * Stylesheet for disabling a global styles duotone filter.
- *
- * @param {Object} props Duotone props.
- * @param {string} props.selector Selector to disable the filter for.
- *
- * @return {WPElement} Filter none style element.
- */
-function DuotoneUnsetStylesheet( { selector } ) {
- const css = `
-${ selector } {
- filter: none;
-}
-`;
- return ;
-}
-
-/**
- * The SVG part of the duotone filter.
- *
- * @param {Object} props Duotone props.
- * @param {string} props.id Unique id for this duotone filter.
- * @param {string[]} props.colors Color strings from dark to light.
- *
- * @return {WPElement} Duotone SVG.
- */
-function DuotoneFilter( { id, colors } ) {
- const values = getValuesFromColors( colors );
- return (
-
- );
-}
-
/**
* SVG and stylesheet needed for rendering the duotone filter.
*
@@ -374,15 +250,6 @@ const withDuotoneStyles = createHigherOrderComponent(
'withDuotoneStyles'
);
-export function PresetDuotoneFilter( { preset } ) {
- return (
-
- );
-}
-
addFilter(
'blocks.registerBlockType',
'core/editor/duotone/add-attributes',
diff --git a/packages/block-editor/src/hooks/index.js b/packages/block-editor/src/hooks/index.js
index 36c3181092a17a..f95d4771a1c3b9 100644
--- a/packages/block-editor/src/hooks/index.js
+++ b/packages/block-editor/src/hooks/index.js
@@ -20,4 +20,3 @@ export { getBorderClassesAndStyles, useBorderProps } from './use-border-props';
export { getColorClassesAndStyles, useColorProps } from './use-color-props';
export { getSpacingClassesAndStyles } from './use-spacing-props';
export { useCachedTruthy } from './use-cached-truthy';
-export { PresetDuotoneFilter } from './duotone';
diff --git a/packages/block-editor/src/index.js b/packages/block-editor/src/index.js
index 594c78859b25c8..b2fe8aec5e1ff0 100644
--- a/packages/block-editor/src/index.js
+++ b/packages/block-editor/src/index.js
@@ -3,7 +3,6 @@
*/
import './hooks';
export {
- PresetDuotoneFilter as __unstablePresetDuotoneFilter,
getBorderClassesAndStyles as __experimentalGetBorderClassesAndStyles,
useBorderProps as __experimentalUseBorderProps,
getColorClassesAndStyles as __experimentalGetColorClassesAndStyles,