From db67a793057654a53b1ebc6bbff652b7a47cf1f5 Mon Sep 17 00:00:00 2001
From: Ella <4710635+ellatrix@users.noreply.github.com>
Date: Fri, 21 Jul 2023 13:14:26 +0200
Subject: [PATCH] Allow styles to be changed dynamically through editor
settings (#52767)
---
.../iframed-enqueue-block-editor-settings.php | 19 +++
...amed-enqueue-block-editor-settings.test.js | 108 ++++++++++++++++++
.../edit-post/src/components/layout/index.js | 49 +++++++-
packages/edit-post/src/editor.js | 44 +------
4 files changed, 175 insertions(+), 45 deletions(-)
create mode 100644 packages/e2e-tests/plugins/iframed-enqueue-block-editor-settings.php
create mode 100644 packages/e2e-tests/specs/editor/plugins/iframed-enqueue-block-editor-settings.test.js
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 87fc0aa408516..e3000ae77b863 100644
--- a/packages/edit-post/src/components/layout/index.js
+++ b/packages/edit-post/src/components/layout/index.js
@@ -18,7 +18,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';
@@ -51,6 +54,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. */
@@ -65,7 +71,7 @@ const interfaceLabels = {
footer: __( 'Editor footer' ),
};
-function Layout( { styles } ) {
+function Layout() {
const isMobileViewport = useViewportMatch( 'medium', '<' );
const isHugeViewport = useViewportMatch( 'huge', '>=' );
const isLargeViewport = useViewportMatch( 'large' );
@@ -89,10 +95,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(),
@@ -125,6 +166,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 } ) {
-
+