diff --git a/packages/e2e-tests/plugins/iframed-enqueue-block-editor-settings.php b/packages/e2e-tests/plugins/iframed-enqueue-block-editor-settings.php new file mode 100644 index 0000000000000..2e5eb32c04278 --- /dev/null +++ b/packages/e2e-tests/plugins/iframed-enqueue-block-editor-settings.php @@ -0,0 +1,19 @@ + 'p { border: 1px solid red }', + '__unstableType' => 'plugin', + ); + return $settings; + } +); diff --git a/packages/e2e-tests/specs/editor/plugins/iframed-enqueue-block-editor-settings.test.js b/packages/e2e-tests/specs/editor/plugins/iframed-enqueue-block-editor-settings.test.js new file mode 100644 index 0000000000000..df6eb4bf84032 --- /dev/null +++ b/packages/e2e-tests/specs/editor/plugins/iframed-enqueue-block-editor-settings.test.js @@ -0,0 +1,108 @@ +/** + * WordPress dependencies + */ +import { + activatePlugin, + createNewPost, + deactivatePlugin, + canvas, + activateTheme, +} from '@wordpress/e2e-test-utils'; + +async function getComputedStyle( context, selector, property ) { + return await context.evaluate( + ( sel, prop ) => + window.getComputedStyle( document.querySelector( sel ) )[ prop ], + selector, + property + ); +} + +describe( 'iframed block editor settings styles', () => { + beforeEach( async () => { + // Activate the empty theme (block based theme), which is iframed. + await activateTheme( 'emptytheme' ); + await activatePlugin( + 'gutenberg-test-iframed-enqueue-block-editor-settings' + ); + await createNewPost(); + } ); + + afterEach( async () => { + await deactivatePlugin( + 'gutenberg-test-iframed-enqueue-block-editor-settings' + ); + await activateTheme( 'twentytwentyone' ); + } ); + + it( 'should load styles added through block editor settings', async () => { + await page.waitForSelector( 'iframe[name="editor-canvas"]' ); + // Expect a red border (added in PHP). + expect( await getComputedStyle( canvas(), 'p', 'border-color' ) ).toBe( + 'rgb(255, 0, 0)' + ); + + await page.evaluate( () => { + const settings = window.wp.data + .select( 'core/editor' ) + .getEditorSettings(); + wp.data.dispatch( 'core/editor' ).updateEditorSettings( { + ...settings, + styles: [ + ...settings.styles, + { + css: 'p { border-width: 2px; }', + __unstableType: 'plugin', + }, + ], + } ); + } ); + + // Expect a 2px border (added in JS). + expect( await getComputedStyle( canvas(), 'p', 'border-width' ) ).toBe( + '2px' + ); + } ); + + it( 'should load theme styles added through block editor settings', async () => { + await page.waitForSelector( 'iframe[name="editor-canvas"]' ); + + await page.evaluate( () => { + // Make sure that theme styles are added even if the theme styles + // preference is off. + window.wp.data + .dispatch( 'core/edit-post' ) + .toggleFeature( 'themeStyles' ); + const settings = window.wp.data + .select( 'core/editor' ) + .getEditorSettings(); + wp.data.dispatch( 'core/editor' ).updateEditorSettings( { + ...settings, + styles: [ + ...settings.styles, + { + css: 'p { border-width: 2px; }', + __unstableType: 'theme', + }, + ], + } ); + } ); + + // Expect a 1px border because theme styles are disabled. + expect( await getComputedStyle( canvas(), 'p', 'border-width' ) ).toBe( + '1px' + ); + + await page.evaluate( () => { + // Now enable theme styles. + window.wp.data + .dispatch( 'core/edit-post' ) + .toggleFeature( 'themeStyles' ); + } ); + + // Expect a 2px border because theme styles are enabled. + expect( await getComputedStyle( canvas(), 'p', 'border-width' ) ).toBe( + '2px' + ); + } ); +} ); diff --git a/packages/edit-post/src/components/layout/index.js b/packages/edit-post/src/components/layout/index.js index b7aa8bcd025af..73e050af14df2 100644 --- a/packages/edit-post/src/components/layout/index.js +++ b/packages/edit-post/src/components/layout/index.js @@ -17,7 +17,10 @@ import { store as editorStore, } from '@wordpress/editor'; import { useSelect, useDispatch } from '@wordpress/data'; -import { BlockBreadcrumb } from '@wordpress/block-editor'; +import { + BlockBreadcrumb, + privateApis as blockEditorPrivateApis, +} from '@wordpress/block-editor'; import { Button, ScrollLock, Popover } from '@wordpress/components'; import { useViewportMatch } from '@wordpress/compose'; import { PluginArea } from '@wordpress/plugins'; @@ -50,6 +53,9 @@ import WelcomeGuide from '../welcome-guide'; import ActionsPanel from './actions-panel'; import StartPageOptions from '../start-page-options'; import { store as editPostStore } from '../../store'; +import { unlock } from '../../lock-unlock'; + +const { getLayoutStyles } = unlock( blockEditorPrivateApis ); const interfaceLabels = { /* translators: accessibility text for the editor top bar landmark region. */ @@ -64,7 +70,7 @@ const interfaceLabels = { footer: __( 'Editor footer' ), }; -function Layout( { styles } ) { +function Layout() { const isMobileViewport = useViewportMatch( 'medium', '<' ); const isHugeViewport = useViewportMatch( 'huge', '>=' ); const isLargeViewport = useViewportMatch( 'large' ); @@ -88,10 +94,45 @@ function Layout( { styles } ) { showBlockBreadcrumbs, isTemplateMode, documentLabel, + styles, } = useSelect( ( select ) => { const { getEditorSettings, getPostTypeLabel } = select( editorStore ); + const { isFeatureActive } = select( editPostStore ); const editorSettings = getEditorSettings(); const postTypeLabel = getPostTypeLabel(); + const hasThemeStyles = isFeatureActive( 'themeStyles' ); + + const themeStyles = []; + const presetStyles = []; + editorSettings.styles?.forEach( ( style ) => { + if ( ! style.__unstableType || style.__unstableType === 'theme' ) { + themeStyles.push( style ); + } else { + presetStyles.push( style ); + } + } ); + + const defaultEditorStyles = [ + ...editorSettings.defaultEditorStyles, + ...presetStyles, + ]; + + // If theme styles are not present or displayed, ensure that + // base layout styles are still present in the editor. + if ( + ! editorSettings.disableLayoutStyles && + ! ( hasThemeStyles && themeStyles.length ) + ) { + defaultEditorStyles.push( { + css: getLayoutStyles( { + style: {}, + selector: 'body', + hasBlockGapSupport: false, + hasFallbackGapSupport: true, + fallbackGapValue: '0.5em', + } ), + } ); + } return { isTemplateMode: select( editPostStore ).isEditingTemplate(), @@ -124,6 +165,10 @@ function Layout( { styles } ) { ), // translators: Default label for the Document in the Block Breadcrumb. documentLabel: postTypeLabel || _x( 'Document', 'noun' ), + styles: + hasThemeStyles && themeStyles.length + ? editorSettings.styles + : defaultEditorStyles, }; }, [] ); diff --git a/packages/edit-post/src/editor.js b/packages/edit-post/src/editor.js index bab3c42c979ae..00bc911dd7626 100644 --- a/packages/edit-post/src/editor.js +++ b/packages/edit-post/src/editor.js @@ -9,7 +9,6 @@ import { store as editorStore, privateApis as editorPrivateApis, } from '@wordpress/editor'; -import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; import { useMemo } from '@wordpress/element'; import { SlotFillProvider } from '@wordpress/components'; import { store as coreStore } from '@wordpress/core-data'; @@ -28,7 +27,6 @@ import { unlock } from './lock-unlock'; import useCommonCommands from './hooks/commands/use-common-commands'; const { ExperimentalEditorProvider } = unlock( editorPrivateApis ); -const { getLayoutStyles } = unlock( blockEditorPrivateApis ); const { useCommands } = unlock( coreCommandsPrivateApis ); function Editor( { postId, postType, settings, initialEdits, ...props } ) { @@ -39,7 +37,6 @@ function Editor( { postId, postType, settings, initialEdits, ...props } ) { focusMode, isDistractionFree, hasInlineToolbar, - hasThemeStyles, post, preferredStyleVariations, hiddenBlockTypes, @@ -83,7 +80,6 @@ function Editor( { postId, postType, settings, initialEdits, ...props } ) { focusMode: isFeatureActive( 'focusMode' ), isDistractionFree: isFeatureActive( 'distractionFree' ), hasInlineToolbar: isFeatureActive( 'inlineToolbar' ), - hasThemeStyles: isFeatureActive( 'themeStyles' ), preferredStyleVariations: select( preferencesStore ).get( 'core/edit-post', 'preferredStyleVariations' @@ -155,44 +151,6 @@ function Editor( { postId, postType, settings, initialEdits, ...props } ) { keepCaretInsideBlock, ] ); - const styles = useMemo( () => { - const themeStyles = []; - const presetStyles = []; - settings.styles?.forEach( ( style ) => { - if ( ! style.__unstableType || style.__unstableType === 'theme' ) { - themeStyles.push( style ); - } else { - presetStyles.push( style ); - } - } ); - - const defaultEditorStyles = [ - ...settings.defaultEditorStyles, - ...presetStyles, - ]; - - // If theme styles are not present or displayed, ensure that - // base layout styles are still present in the editor. - if ( - ! settings.disableLayoutStyles && - ! ( hasThemeStyles && themeStyles.length ) - ) { - defaultEditorStyles.push( { - css: getLayoutStyles( { - style: {}, - selector: 'body', - hasBlockGapSupport: false, - hasFallbackGapSupport: true, - fallbackGapValue: '0.5em', - } ), - } ); - } - - return hasThemeStyles && themeStyles.length - ? settings.styles - : defaultEditorStyles; - }, [ settings, hasThemeStyles ] ); - if ( ! post ) { return null; } @@ -211,7 +169,7 @@ function Editor( { postId, postType, settings, initialEdits, ...props } ) { - +