Skip to content

Commit

Permalink
Components: Fix Slot/Fill Emotion StyleProvider (#38237)
Browse files Browse the repository at this point in the history
* Fix Slot/Fill emotion style provider

* Add slotfill storybook example to `useCx`

* Use iframe from `@wordpress/block-editor`, add `bubblesVirtually` prop

* Fix slotfill name

* Add simpler slotfill example
  • Loading branch information
ciampo authored Jan 28, 2022
1 parent efa395e commit d8ab9a1
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 47 deletions.
13 changes: 12 additions & 1 deletion packages/components/src/slot-fill/bubbles-virtually/fill.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useRef, useState, useEffect, createPortal } from '@wordpress/element';
* Internal dependencies
*/
import useSlot from './use-slot';
import StyleProvider from '../../style-provider';

function useForceUpdate() {
const [ , setState ] = useState( {} );
Expand Down Expand Up @@ -48,5 +49,15 @@ export default function Fill( { name, children } ) {
children = children( slot.fillProps );
}

return createPortal( children, slot.ref.current );
// When using a `Fill`, the `children` will be rendered in the document of the
// `Slot`. This means that we need to wrap the `children` in a `StyleProvider`
// to make sure we're referencing the right document/iframe (instead of the
// context of the `Fill`'s parent).
const wrappedChildren = (
<StyleProvider document={ slot.ref.current.ownerDocument }>
{ children }
</StyleProvider>
);

return createPortal( wrappedChildren, slot.ref.current );
}
120 changes: 74 additions & 46 deletions packages/components/src/utils/hooks/stories/use-cx.js
Original file line number Diff line number Diff line change
@@ -1,79 +1,107 @@
/**
* Internal dependencies
* External dependencies
*/
import { useCx } from '..';
import StyleProvider from '../../../style-provider';
import { css } from '@emotion/react';

/**
* WordPress dependencies
*/
import { useState, createPortal } from '@wordpress/element';
import { __unstableIframe as Iframe } from '@wordpress/block-editor';

/**
* External dependencies
* Internal dependencies
*/
import { css } from '@emotion/react';
import { useCx } from '..';
import StyleProvider from '../../../style-provider';
import {
createSlotFill,
Provider as SlotFillProvider,
} from '../../../slot-fill';

export default {
title: 'Components (Experimental)/useCx',
};

const IFrame = ( { children } ) => {
const [ iframeDocument, setIframeDocument ] = useState();

const handleRef = ( node ) => {
if ( ! node ) {
return null;
}
const Example = ( { args, children } ) => {
const cx = useCx();
const classes = cx( ...args );
return <span className={ classes }>{ children }</span>;
};

function setIfReady() {
const { contentDocument } = node;
const { readyState } = contentDocument;
export const _slotFill = () => {
const { Fill, Slot } = createSlotFill( 'UseCxExampleSlot' );

if ( readyState !== 'interactive' && readyState !== 'complete' ) {
return false;
}
const redText = css`
color: red;
`;
const blueText = css`
color: blue;
`;
const greenText = css`
color: green;
`;

setIframeDocument( contentDocument );
}
return (
<SlotFillProvider>
<StyleProvider document={ document }>
<Iframe>
<Iframe>
<Example args={ [ redText ] }>
This text is inside an iframe and should be red
</Example>
<Fill name="test-slot">
<Example args={ [ blueText ] }>
This text is also inside the iframe, but is
relocated by a slot/fill and should be blue
</Example>
</Fill>
<Fill name="outside-frame">
<Example args={ [ greenText ] }>
This text is also inside the iframe, but is
relocated by a slot/fill and should be green
</Example>
</Fill>
</Iframe>
<StyleProvider document={ document }>
<Slot bubblesVirtually name="test-slot" />
</StyleProvider>
</Iframe>
<Slot bubblesVirtually name="outside-frame" />
</StyleProvider>
</SlotFillProvider>
);
};

if ( setIfReady() ) {
return;
}
export const _slotFillSimple = () => {
const { Fill, Slot } = createSlotFill( 'UseCxExampleSlotTwo' );

node.addEventListener( 'load', () => {
// iframe isn't immediately ready in Firefox
setIfReady();
} );
};
const redText = css`
color: red;
`;

return (
<iframe ref={ handleRef } title="use-cx-test-frame">
{ iframeDocument &&
createPortal(
<StyleProvider document={ iframeDocument }>
{ children }
</StyleProvider>,
iframeDocument.body
) }
</iframe>
<SlotFillProvider>
<Iframe>
<Fill name="test-slot">
<Example args={ [ redText ] }>
This text should be red
</Example>
</Fill>
</Iframe>
<Slot bubblesVirtually name="test-slot" />
</SlotFillProvider>
);
};

const Example = ( { args, children } ) => {
const cx = useCx();
const classes = cx( ...args );
return <span className={ classes }>{ children }</span>;
};

export const _default = () => {
const redText = css`
color: red;
`;
return (
<IFrame>
<Iframe>
<Example args={ [ redText ] }>
This text is inside an iframe and is red!
</Example>
</IFrame>
</Iframe>
);
};

0 comments on commit d8ab9a1

Please sign in to comment.