diff --git a/packages/block-editor/src/components/block-preview/index.js b/packages/block-editor/src/components/block-preview/index.js index cf0937507be095..0fb7f55b9955d2 100644 --- a/packages/block-editor/src/components/block-preview/index.js +++ b/packages/block-editor/src/components/block-preview/index.js @@ -16,6 +16,7 @@ import deprecated from '@wordpress/deprecated'; */ import { ExperimentalBlockEditorProvider } from '../provider'; import AutoHeightBlockPreview from './auto'; +import EditorStyles from '../editor-styles'; import { store as blockEditorStore } from '../../store'; import { BlockListItems } from '../block-list'; @@ -113,7 +114,11 @@ export function useBlockPreview( { blocks, props = {}, layout } ) { [] ); const settings = useMemo( - () => ( { ...originalSettings, __unstableIsPreviewMode: true } ), + () => ( { + ...originalSettings, + styles: undefined, // Clear styles included by the parent settings, as they are already output by the parent's EditorStyles. + __unstableIsPreviewMode: true, + } ), [ originalSettings ] ); const disabledRef = useDisabled(); @@ -128,6 +133,7 @@ export function useBlockPreview( { blocks, props = {}, layout } ) { value={ renderedBlocks } settings={ settings } > + ); diff --git a/packages/block-editor/src/hooks/duotone.js b/packages/block-editor/src/hooks/duotone.js index 2bbe18793fe558..39a8979782a0c6 100644 --- a/packages/block-editor/src/hooks/duotone.js +++ b/packages/block-editor/src/hooks/duotone.js @@ -37,11 +37,22 @@ 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 { __unstableUseBlockElement as useBlockElement } from '../components/block-list/use-block-props/use-block-refs'; import { store as blockEditorStore } from '../store'; import { unlock } from '../lock-unlock'; const EMPTY_ARRAY = []; +// Safari does not always update the duotone filter when the duotone colors +// are changed. This browser check is later used to force a re-render of the block +// element to ensure the duotone filter is updated. The check is included at the +// root of this file as it only needs to be run once per page load. +const isSafari = + window?.navigator.userAgent && + window.navigator.userAgent.includes( 'Safari' ) && + ! window.navigator.userAgent.includes( 'Chrome' ) && + ! window.navigator.userAgent.includes( 'Chromium' ); + extend( [ namesPlugin ] ); function useMultiOriginPresets( { presetSetting, defaultSetting } ) { @@ -223,6 +234,7 @@ const withDuotoneControls = createHigherOrderComponent( ); function DuotoneStyles( { + clientId, id: filterId, selector: duotoneSelector, attribute: duotoneAttr, @@ -278,6 +290,8 @@ function DuotoneStyles( { useDispatch( blockEditorStore ) ); + const blockElement = useBlockElement( clientId ); + useEffect( () => { if ( ! isValidFilter ) return; @@ -294,12 +308,30 @@ function DuotoneStyles( { __unstableType: 'svgs', } ); + // Safari does not always update the duotone filter when the duotone colors + // are changed. When using Safari, force the block element to be repainted by + // the browser to ensure any changes are reflected visually. This logic matches + // that used on the site frontend in `block-supports/duotone.php`. + if ( blockElement && isSafari ) { + const display = blockElement.style.display; + // Switch to `inline-block` to force a repaint. In the editor, `inline-block` + // is used instead of `none` to ensure that scroll position is not affected, + // as `none` results in the editor scrolling to the top of the block. + blockElement.style.display = 'inline-block'; + // Simply accessing el.offsetHeight flushes layout and style + // changes in WebKit without having to wait for setTimeout. + // eslint-disable-next-line no-unused-expressions + blockElement.offsetHeight; + blockElement.style.display = display; + } + return () => { deleteStyleOverride( filterId ); deleteStyleOverride( `duotone-${ filterId }` ); }; }, [ isValidFilter, + blockElement, colors, selector, filterId, @@ -378,6 +410,7 @@ const withDuotoneStyles = createHigherOrderComponent( <> { shouldRender && (