WordPress / gutenberg

The Block Editor project for WordPress and beyond. Plugin is available from the official repository.
https://wordpress.org/gutenberg/
Other
10.3k stars 4.11k forks source link

Emotion styles for react components in blocks are broken in front-end editor #38226

Open brianhogg opened 2 years ago

brianhogg commented 2 years ago

Description

Components like react-select (styled with the emotion library) do not have their styles applied when the block is added through the front-end editor. However, it looks fine in the back-end editor.

Step-by-step reproduction instructions

  1. Install a block that uses a react component with styling (ie. the events calendar shortcode)
  2. Add the block using the front-end full site editor

Any components styled with the react emotion library are broken.

Screenshots, screen recording, code snippet

Screen Shot 2022-01-25 at 5 49 45 PM Screen Shot 2022-01-25 at 5 49 09 PM

Environment info

Please confirm that you have searched existing issues in the repo.

Yes

Please confirm that you have tested with all plugins deactivated except Gutenberg.

Yes

brianhogg commented 2 years ago

Confirmed the issue exists on other block themes, ie. the FrostWP theme, so it's not specific to full site editing in the Twenty Twenty-Two theme.

sthielen commented 2 years ago

Curious if you were able to resolve this? We're seeing the same issue with a block that uses styled-components. Looks like it's related to the way the template editor uses iframes, per this thread.

thomaslc08 commented 1 year ago

Hi! Were you able to resolve this? I have this issue on WordPress 6.1 with styled-components. It works fine with the Gutenberg editor for a page or a post but not in full site editing mode

brianhogg commented 1 year ago

I ended up having to manually grab the CSS generated for each of the HTML elements and pull it over into a CSS stylesheet. So would need to grab an old version of The Events Calendar Shortcode to see the original issue from the screenshots.

ajgagnon commented 1 year ago

Here's a workaround, though it's a bit verbose. I've replicated the <StyleProvider> component used by the Gutenberg Modal inside iframes:

/**
 * External dependencies
 */
import { CacheProvider } from '@emotion/react';
import createCache from '@emotion/cache';
import memoize from 'memize';
import * as uuid from 'uuid';
import { useRef } from 'react';

const uuidCache = new Set();

const memoizedCreateCacheWithContainer = memoize((container) => {
    // Emotion only accepts alphabetical and hyphenated keys so we just
    // strip the numbers from the UUID. It _should_ be fine.
    let key = uuid.v4().replace(/[0-9]/g, '');
    while (uuidCache.has(key)) {
        key = uuid.v4().replace(/[0-9]/g, '');
    }
    uuidCache.add(key);
    return createCache({ container, key });
});

export function StyleProvider(props) {
    const { children, document } = props;
    const ref = useRef();

    if (!document) {
        return null;
    }

    const cache = memoizedCreateCacheWithContainer(document.head);

    return (
        <CacheProvider ref={ref} value={cache}>
            {children}
        </CacheProvider>
    );
}

export default StyleProvider;

Then in your component, you will need to wrap your css declarations in this component, and pass a ref to the ownerDocument. It will also catch any inner blocks here too, so you only need to do it in a wrapper component.

import { useRef } from "@wordpress/element";

export default ({ attributes, setAttributes }) => {
   const ref = useRef();
   const blockProps = useBlockProps({ ref });

   return (
     <div {...blockProps}>
         <StyleProvider document={ref?.current?.ownerDocument}>
            <div css={css`background: black;`}>

            </div>
         </StyleProvider>
     </div>
   );
}