From a8c5605f5dd077a601aefce6f58409f54d7d4447 Mon Sep 17 00:00:00 2001 From: Ella <4710635+ellatrix@users.noreply.github.com> Date: Thu, 14 Sep 2023 16:34:12 +0300 Subject: [PATCH] Block editor: remove `__unstableElementContext` and filter `EditorStyles` instead (#52888) --- .../src/components/duotone/components.js | 133 ------------------ .../src/components/duotone/index.js | 7 - .../src/components/duotone/utils.js | 65 +++++++++ .../src/components/editor-styles/index.js | 42 ++++-- .../global-styles/use-global-styles-output.js | 12 +- packages/block-editor/src/components/index.js | 1 - packages/block-editor/src/hooks/duotone.js | 85 ++++++----- .../block-editor/src/store/private-actions.js | 15 ++ .../src/store/private-selectors.js | 11 ++ packages/block-editor/src/store/reducer.js | 22 +++ 10 files changed, 187 insertions(+), 206 deletions(-) delete mode 100644 packages/block-editor/src/components/duotone/components.js delete mode 100644 packages/block-editor/src/components/duotone/index.js diff --git a/packages/block-editor/src/components/duotone/components.js b/packages/block-editor/src/components/duotone/components.js deleted file mode 100644 index 471c03502c588c..00000000000000 --- a/packages/block-editor/src/components/duotone/components.js +++ /dev/null @@ -1,133 +0,0 @@ -/** - * 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 deleted file mode 100644 index 919d67780d7c7d..00000000000000 --- a/packages/block-editor/src/components/duotone/index.js +++ /dev/null @@ -1,7 +0,0 @@ -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 index d7cbd0ccba26e9..ac58eca18bb9f8 100644 --- a/packages/block-editor/src/components/duotone/utils.js +++ b/packages/block-editor/src/components/duotone/utils.js @@ -23,3 +23,68 @@ export function getValuesFromColors( colors = [] ) { return values; } + +/** + * Stylesheet for disabling a global styles duotone filter. + * + * @param {string} selector Selector to disable the filter for. + * + * @return {string} Filter none style. + */ +export function getDuotoneUnsetStylesheet( selector ) { + return `${ selector }{filter:none}`; +} + +/** + * SVG and stylesheet needed for rendering the duotone filter. + * + * @param {string} selector Selector to apply the filter to. + * @param {string} id Unique id for this duotone filter. + * + * @return {string} Duotone filter style. + */ +export function getDuotoneStylesheet( selector, id ) { + return `${ selector }{filter:url(#${ id })}`; +} + +/** + * The SVG part of the duotone filter. + * + * @param {string} id Unique id for this duotone filter. + * @param {string[]} colors Color strings from dark to light. + * + * @return {string} Duotone SVG. + */ +export function getDuotoneFilter( id, colors ) { + const values = getValuesFromColors( colors ); + return ` +`; +} diff --git a/packages/block-editor/src/components/editor-styles/index.js b/packages/block-editor/src/components/editor-styles/index.js index 08005ae83a99b1..85c54109d0231b 100644 --- a/packages/block-editor/src/components/editor-styles/index.js +++ b/packages/block-editor/src/components/editor-styles/index.js @@ -10,11 +10,14 @@ import a11yPlugin from 'colord/plugins/a11y'; */ import { SVG } from '@wordpress/components'; import { useCallback, useMemo } from '@wordpress/element'; +import { useSelect } from '@wordpress/data'; /** * Internal dependencies */ import transformStyles from '../../utils/transform-styles'; +import { store as blockEditorStore } from '../../store'; +import { unlock } from '../../lock-unlock'; extend( [ namesPlugin, a11yPlugin ] ); @@ -65,33 +68,42 @@ function useDarkThemeBodyClassName( styles, scope ) { } export default function EditorStyles( { styles, scope } ) { - const stylesArray = useMemo( - () => Object.values( styles ?? [] ), - [ styles ] + const overrides = useSelect( + ( select ) => unlock( select( blockEditorStore ) ).getStyleOverrides(), + [] ); - const transformedStyles = useMemo( - () => + const [ transformedStyles, transformedSvgs ] = useMemo( () => { + const _styles = Object.values( styles ?? [] ); + + for ( const [ id, override ] of overrides ) { + const index = _styles.findIndex( ( { id: _id } ) => id === _id ); + const overrideWithId = { ...override, id }; + if ( index === -1 ) { + _styles.push( overrideWithId ); + } else { + _styles[ index ] = overrideWithId; + } + } + + return [ transformStyles( - stylesArray.filter( ( style ) => style?.css ), + _styles.filter( ( style ) => style?.css ), scope ), - [ stylesArray, scope ] - ); - - const transformedSvgs = useMemo( - () => - stylesArray + _styles .filter( ( style ) => style.__unstableType === 'svgs' ) .map( ( style ) => style.assets ) .join( '' ), - [ stylesArray ] - ); + ]; + }, [ styles, overrides, scope ] ); return ( <> { /* Use an empty style element to have a document reference, but this could be any element. */ } - ) ) } diff --git a/packages/block-editor/src/components/global-styles/use-global-styles-output.js b/packages/block-editor/src/components/global-styles/use-global-styles-output.js index e8cdd332e9cce6..01c4f5b8781d75 100644 --- a/packages/block-editor/src/components/global-styles/use-global-styles-output.js +++ b/packages/block-editor/src/components/global-styles/use-global-styles-output.js @@ -9,7 +9,7 @@ import { store as blocksStore, } from '@wordpress/blocks'; import { useSelect } from '@wordpress/data'; -import { renderToString, useContext, useMemo } from '@wordpress/element'; +import { useContext, useMemo } from '@wordpress/element'; import { getCSSRules } from '@wordpress/style-engine'; /** @@ -23,7 +23,7 @@ import { } from './typography-utils'; import { GlobalStylesContext } from './context'; import { useGlobalSetting } from './hooks'; -import { PresetDuotoneFilter } from '../duotone/components'; +import { getDuotoneFilter } from '../duotone/utils'; import { getGapCSSValue } from '../../hooks/gap'; import { store as blockEditorStore } from '../../store'; import { LAYOUT_DEFINITIONS } from '../../layouts/definitions'; @@ -164,11 +164,9 @@ function getPresetsSvgFilters( blockPresets = {} ) { .filter( ( origin ) => presetByOrigin[ origin ] ) .flatMap( ( origin ) => presetByOrigin[ origin ].map( ( preset ) => - renderToString( - + getDuotoneFilter( + `wp-duotone-${ preset.slug }`, + preset.colors ) ) ) diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js index 7be30aa5a858ba..6edcd460e31ac4 100644 --- a/packages/block-editor/src/components/index.js +++ b/packages/block-editor/src/components/index.js @@ -5,7 +5,6 @@ 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 2ecd35c99ee8c4..2bbe18793fe558 100644 --- a/packages/block-editor/src/hooks/duotone.js +++ b/packages/block-editor/src/hooks/duotone.js @@ -15,7 +15,8 @@ import { } from '@wordpress/blocks'; import { createHigherOrderComponent, useInstanceId } from '@wordpress/compose'; import { addFilter } from '@wordpress/hooks'; -import { useMemo, useContext, createPortal } from '@wordpress/element'; +import { useMemo, useEffect } from '@wordpress/element'; +import { useDispatch } from '@wordpress/data'; /** * Internal dependencies @@ -26,45 +27,23 @@ import { __experimentalDuotoneControl as DuotoneControl, useSetting, } from '../components'; -import BlockList from '../components/block-list'; import { - __unstableDuotoneFilter as DuotoneFilter, - __unstableDuotoneStylesheet as DuotoneStylesheet, - __unstableDuotoneUnsetStylesheet as DuotoneUnsetStylesheet, -} from '../components/duotone'; + getDuotoneFilter, + getDuotoneStylesheet, + getDuotoneUnsetStylesheet, +} from '../components/duotone/utils'; import { getBlockCSSSelector } from '../components/global-styles/get-block-css-selector'; import { scopeSelector } from '../components/global-styles/utils'; import { useBlockSettings } from './utils'; import { default as StylesFiltersPanel } from '../components/global-styles/filters-panel'; import { useBlockEditingMode } from '../components/block-editing-mode'; +import { store as blockEditorStore } from '../store'; +import { unlock } from '../lock-unlock'; const EMPTY_ARRAY = []; extend( [ namesPlugin ] ); -/** - * 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. - * @param {string[]|"unset"} props.colors Array of RGB color strings ordered from dark to light. - * - * @return {WPElement} Duotone element. - */ -function InlineDuotone( { selector, id, colors } ) { - if ( colors === 'unset' ) { - return ; - } - - return ( - <> - - - - ); -} - function useMultiOriginPresets( { presetSetting, defaultSetting } ) { const disableDefault = ! useSetting( defaultSetting ); const userPresets = @@ -248,8 +227,6 @@ function DuotoneStyles( { selector: duotoneSelector, attribute: duotoneAttr, } ) { - const element = useContext( BlockList.__unstableElementContext ); - const duotonePalette = useMultiOriginPresets( { presetSetting: 'color.duotone', defaultSetting: 'color.defaultDuotone', @@ -290,25 +267,47 @@ function DuotoneStyles( { // Assuming the selector part is a subclass selector (not a tag name) // so we can prepend the filter id class. If we want to support elements // such as `img` or namespaces, we'll need to add a case for that here. - return `.editor-styles-wrapper .${ filterId }${ selectorPart.trim() }`; + return `.${ filterId }${ selectorPart.trim() }`; } ); const selector = selectorsScoped.join( ', ' ); const isValidFilter = Array.isArray( colors ) || colors === 'unset'; - return ( - element && - isValidFilter && - createPortal( - , - element - ) + const { setStyleOverride, deleteStyleOverride } = unlock( + useDispatch( blockEditorStore ) ); + + useEffect( () => { + if ( ! isValidFilter ) return; + + setStyleOverride( filterId, { + css: + colors !== 'unset' + ? getDuotoneStylesheet( selector, filterId ) + : getDuotoneUnsetStylesheet( selector ), + __unstableType: 'presets', + } ); + setStyleOverride( `duotone-${ filterId }`, { + assets: + colors !== 'unset' ? getDuotoneFilter( filterId, colors ) : '', + __unstableType: 'svgs', + } ); + + return () => { + deleteStyleOverride( filterId ); + deleteStyleOverride( `duotone-${ filterId }` ); + }; + }, [ + isValidFilter, + colors, + selector, + filterId, + setStyleOverride, + deleteStyleOverride, + ] ); + + return null; } /** diff --git a/packages/block-editor/src/store/private-actions.js b/packages/block-editor/src/store/private-actions.js index 0171b4f442d197..dc62614b576812 100644 --- a/packages/block-editor/src/store/private-actions.js +++ b/packages/block-editor/src/store/private-actions.js @@ -275,3 +275,18 @@ export function setOpenedBlockSettingsMenu( clientId ) { clientId, }; } + +export function setStyleOverride( id, style ) { + return { + type: 'SET_STYLE_OVERRIDE', + id, + style, + }; +} + +export function deleteStyleOverride( id ) { + return { + type: 'DELETE_STYLE_OVERRIDE', + id, + }; +} diff --git a/packages/block-editor/src/store/private-selectors.js b/packages/block-editor/src/store/private-selectors.js index 2dc5ad8360fa33..e77e478ba60466 100644 --- a/packages/block-editor/src/store/private-selectors.js +++ b/packages/block-editor/src/store/private-selectors.js @@ -149,3 +149,14 @@ export function getBlockRemovalRules( state ) { export function getOpenedBlockSettingsMenu( state ) { return state.openedBlockSettingsMenu; } + +/** + * Returns all style overrides, intended to be merged with global editor styles. + * + * @param {Object} state Global application state. + * + * @return {Map} A map of style IDs to style overrides. + */ +export function getStyleOverrides( state ) { + return state.styleOverrides; +} diff --git a/packages/block-editor/src/store/reducer.js b/packages/block-editor/src/store/reducer.js index 4d1713ebcd0e0f..18048ce138eb23 100644 --- a/packages/block-editor/src/store/reducer.js +++ b/packages/block-editor/src/store/reducer.js @@ -1928,6 +1928,27 @@ export function openedBlockSettingsMenu( state = null, action ) { return state; } +/** + * Reducer returning a map of style IDs to style overrides. + * + * @param {Map} state Current state. + * @param {Object} action Dispatched action. + * + * @return {Map} Updated state. + */ +export function styleOverrides( state = new Map(), action ) { + switch ( action.type ) { + case 'SET_STYLE_OVERRIDE': + return new Map( state ).set( action.id, action.style ); + case 'DELETE_STYLE_OVERRIDE': { + const newState = new Map( state ); + newState.delete( action.id ); + return newState; + } + } + return state; +} + const combinedReducers = combineReducers( { blocks, isTyping, @@ -1951,6 +1972,7 @@ const combinedReducers = combineReducers( { temporarilyEditingAsBlocks, blockVisibility, blockEditingModes, + styleOverrides, removalPromptData, blockRemovalRules, openedBlockSettingsMenu,