Skip to content

Commit d8ab9a1

Browse files
authored
Components: Fix Slot/Fill Emotion StyleProvider (#38237)
* 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
1 parent efa395e commit d8ab9a1

File tree

2 files changed

+86
-47
lines changed
  • packages/components/src

2 files changed

+86
-47
lines changed

packages/components/src/slot-fill/bubbles-virtually/fill.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { useRef, useState, useEffect, createPortal } from '@wordpress/element';
88
* Internal dependencies
99
*/
1010
import useSlot from './use-slot';
11+
import StyleProvider from '../../style-provider';
1112

1213
function useForceUpdate() {
1314
const [ , setState ] = useState( {} );
@@ -48,5 +49,15 @@ export default function Fill( { name, children } ) {
4849
children = children( slot.fillProps );
4950
}
5051

51-
return createPortal( children, slot.ref.current );
52+
// When using a `Fill`, the `children` will be rendered in the document of the
53+
// `Slot`. This means that we need to wrap the `children` in a `StyleProvider`
54+
// to make sure we're referencing the right document/iframe (instead of the
55+
// context of the `Fill`'s parent).
56+
const wrappedChildren = (
57+
<StyleProvider document={ slot.ref.current.ownerDocument }>
58+
{ children }
59+
</StyleProvider>
60+
);
61+
62+
return createPortal( wrappedChildren, slot.ref.current );
5263
}
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,107 @@
11
/**
2-
* Internal dependencies
2+
* External dependencies
33
*/
4-
import { useCx } from '..';
5-
import StyleProvider from '../../../style-provider';
4+
import { css } from '@emotion/react';
65

76
/**
87
* WordPress dependencies
98
*/
10-
import { useState, createPortal } from '@wordpress/element';
9+
import { __unstableIframe as Iframe } from '@wordpress/block-editor';
10+
1111
/**
12-
* External dependencies
12+
* Internal dependencies
1313
*/
14-
import { css } from '@emotion/react';
14+
import { useCx } from '..';
15+
import StyleProvider from '../../../style-provider';
16+
import {
17+
createSlotFill,
18+
Provider as SlotFillProvider,
19+
} from '../../../slot-fill';
1520

1621
export default {
1722
title: 'Components (Experimental)/useCx',
1823
};
1924

20-
const IFrame = ( { children } ) => {
21-
const [ iframeDocument, setIframeDocument ] = useState();
22-
23-
const handleRef = ( node ) => {
24-
if ( ! node ) {
25-
return null;
26-
}
25+
const Example = ( { args, children } ) => {
26+
const cx = useCx();
27+
const classes = cx( ...args );
28+
return <span className={ classes }>{ children }</span>;
29+
};
2730

28-
function setIfReady() {
29-
const { contentDocument } = node;
30-
const { readyState } = contentDocument;
31+
export const _slotFill = () => {
32+
const { Fill, Slot } = createSlotFill( 'UseCxExampleSlot' );
3133

32-
if ( readyState !== 'interactive' && readyState !== 'complete' ) {
33-
return false;
34-
}
34+
const redText = css`
35+
color: red;
36+
`;
37+
const blueText = css`
38+
color: blue;
39+
`;
40+
const greenText = css`
41+
color: green;
42+
`;
3543

36-
setIframeDocument( contentDocument );
37-
}
44+
return (
45+
<SlotFillProvider>
46+
<StyleProvider document={ document }>
47+
<Iframe>
48+
<Iframe>
49+
<Example args={ [ redText ] }>
50+
This text is inside an iframe and should be red
51+
</Example>
52+
<Fill name="test-slot">
53+
<Example args={ [ blueText ] }>
54+
This text is also inside the iframe, but is
55+
relocated by a slot/fill and should be blue
56+
</Example>
57+
</Fill>
58+
<Fill name="outside-frame">
59+
<Example args={ [ greenText ] }>
60+
This text is also inside the iframe, but is
61+
relocated by a slot/fill and should be green
62+
</Example>
63+
</Fill>
64+
</Iframe>
65+
<StyleProvider document={ document }>
66+
<Slot bubblesVirtually name="test-slot" />
67+
</StyleProvider>
68+
</Iframe>
69+
<Slot bubblesVirtually name="outside-frame" />
70+
</StyleProvider>
71+
</SlotFillProvider>
72+
);
73+
};
3874

39-
if ( setIfReady() ) {
40-
return;
41-
}
75+
export const _slotFillSimple = () => {
76+
const { Fill, Slot } = createSlotFill( 'UseCxExampleSlotTwo' );
4277

43-
node.addEventListener( 'load', () => {
44-
// iframe isn't immediately ready in Firefox
45-
setIfReady();
46-
} );
47-
};
78+
const redText = css`
79+
color: red;
80+
`;
4881

4982
return (
50-
<iframe ref={ handleRef } title="use-cx-test-frame">
51-
{ iframeDocument &&
52-
createPortal(
53-
<StyleProvider document={ iframeDocument }>
54-
{ children }
55-
</StyleProvider>,
56-
iframeDocument.body
57-
) }
58-
</iframe>
83+
<SlotFillProvider>
84+
<Iframe>
85+
<Fill name="test-slot">
86+
<Example args={ [ redText ] }>
87+
This text should be red
88+
</Example>
89+
</Fill>
90+
</Iframe>
91+
<Slot bubblesVirtually name="test-slot" />
92+
</SlotFillProvider>
5993
);
6094
};
6195

62-
const Example = ( { args, children } ) => {
63-
const cx = useCx();
64-
const classes = cx( ...args );
65-
return <span className={ classes }>{ children }</span>;
66-
};
67-
6896
export const _default = () => {
6997
const redText = css`
7098
color: red;
7199
`;
72100
return (
73-
<IFrame>
101+
<Iframe>
74102
<Example args={ [ redText ] }>
75103
This text is inside an iframe and is red!
76104
</Example>
77-
</IFrame>
105+
</Iframe>
78106
);
79107
};

0 commit comments

Comments
 (0)