Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix the styles compatibility hook for the editor iframes #40842

Merged
merged 4 commits into from
May 5, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 62 additions & 54 deletions packages/block-editor/src/components/iframe/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
useState,
createPortal,
forwardRef,
useEffect,
useMemo,
useReducer,
} from '@wordpress/element';
Expand All @@ -34,61 +33,66 @@ const BLOCK_PREFIX = 'wp-block';
*
* Ideally, this hook should be removed in the future and styles should be added
* explicitly as editor styles.
*
* @param {Document} doc The document to append cloned stylesheets to.
*/
function styleSheetsCompat( doc ) {
// Search the document for stylesheets targetting the editor canvas.
Array.from( document.styleSheets ).forEach( ( styleSheet ) => {
try {
// May fail for external styles.
// eslint-disable-next-line no-unused-expressions
styleSheet.cssRules;
} catch ( e ) {
return;
}

const { ownerNode, cssRules } = styleSheet;

if ( ! cssRules ) {
return;
}
function useStylesCompatibility() {
return useRefEffect( ( node ) => {
// Search the document for stylesheets targetting the editor canvas.
Array.from( document.styleSheets ).forEach( ( styleSheet ) => {
try {
// May fail for external styles.
// eslint-disable-next-line no-unused-expressions
styleSheet.cssRules;
} catch ( e ) {
return;
}

// Generally, ignore inline styles. We add inline styles belonging to a
// stylesheet later, which may or may not match the selectors.
if ( ownerNode.tagName !== 'LINK' ) {
return;
}
const { ownerNode, cssRules } = styleSheet;

// Don't try to add the reset styles, which were removed as a dependency
// from `edit-blocks` for the iframe since we don't need to reset admin
// styles.
if ( ownerNode.id === 'wp-reset-editor-styles-css' ) {
return;
}

const isMatch = Array.from( cssRules ).find(
( { selectorText } ) =>
selectorText &&
( selectorText.includes( `.${ BODY_CLASS_NAME }` ) ||
selectorText.includes( `.${ BLOCK_PREFIX }` ) )
);
if ( ! cssRules ) {
return;
}

if ( isMatch && ! doc.getElementById( ownerNode.id ) ) {
// Display warning once we have a way to add style dependencies to the editor.
// See: https://github.com/WordPress/gutenberg/pull/37466.
// Generally, ignore inline styles. We add inline styles belonging to a
// stylesheet later, which may or may not match the selectors.
if ( ownerNode.tagName !== 'LINK' ) {
return;
}

doc.head.appendChild( ownerNode.cloneNode( true ) );
// Don't try to add the reset styles, which were removed as a dependency
// from `edit-blocks` for the iframe since we don't need to reset admin
// styles.
if ( ownerNode.id === 'wp-reset-editor-styles-css' ) {
return;
}

// Add inline styles belonging to the stylesheet.
const inlineCssId = ownerNode.id.replace( '-css', '-inline-css' );
const inlineCssElement = document.getElementById( inlineCssId );
const isMatch = Array.from( cssRules ).find(
( { selectorText } ) =>
selectorText &&
( selectorText.includes( `.${ BODY_CLASS_NAME }` ) ||
selectorText.includes( `.${ BLOCK_PREFIX }` ) )
);

if ( inlineCssElement ) {
doc.head.appendChild( inlineCssElement.cloneNode( true ) );
if (
isMatch &&
! node.ownerDocument.getElementById( ownerNode.id )
) {
// Display warning once we have a way to add style dependencies to the editor.
// See: https://github.com/WordPress/gutenberg/pull/37466.
node.appendChild( ownerNode.cloneNode( true ) );

// Add inline styles belonging to the stylesheet.
const inlineCssId = ownerNode.id.replace(
'-css',
'-inline-css'
);
const inlineCssElement = document.getElementById( inlineCssId );

if ( inlineCssElement ) {
node.appendChild( inlineCssElement.cloneNode( true ) );
}
}
}
} );
} );
}, [] );
}

/**
Expand Down Expand Up @@ -222,12 +226,7 @@ function Iframe(
} );
}, [] );
const bodyRef = useMergeRefs( [ contentRef, clearerRef, writingFlowRef ] );

useEffect( () => {
if ( iframeDocument ) {
styleSheetsCompat( iframeDocument );
}
}, [ iframeDocument ] );
const styleCompatibilityRef = useStylesCompatibility();

head = (
<>
Expand Down Expand Up @@ -275,6 +274,15 @@ function Iframe(
...bodyClasses
) }
>
{ /*
* This is a wrapper for the extra styles and scripts
* rendered imperatively by cloning the parent,
* it's important that this div's content remains uncontrolled.
*/ }
<div
style={ { display: 'none' } }
ref={ styleCompatibilityRef }
/>
<StyleProvider document={ iframeDocument }>
{ children }
</StyleProvider>
Expand Down