Skip to content

Commit

Permalink
Popover: Fix iframe story and add test (#53182)
Browse files Browse the repository at this point in the history
* Popover: Fix iframe story and add test

* Simplify state ref

* Move test utils file

* Fix Firefox case

* Fix iframe in Chrome
  • Loading branch information
mirka committed Aug 9, 2023
1 parent 887f11c commit 054344c
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 46 deletions.
48 changes: 2 additions & 46 deletions packages/components/src/popover/stories/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import { __unstableIframe as Iframe } from '@wordpress/block-editor';
* Internal dependencies
*/
import Button from '../../button';
import { Provider as SlotFillProvider } from '../../slot-fill';
import { Popover } from '..';
import { PopoverInsideIframeRenderedInExternalSlot } from '../test/utils';
import type { PopoverProps } from '../types';

const AVAILABLE_PLACEMENTS: PopoverProps[ 'placement' ][] = [
Expand Down Expand Up @@ -249,51 +249,7 @@ DynamicHeight.args = {
export const WithSlotOutsideIframe: ComponentStory< typeof Popover > = (
args
) => {
const anchorRef = useRef( null );
const slotName = 'popover-with-slot-outside-iframe';

return (
<SlotFillProvider>
<div>
{ /* @ts-expect-error Slot is not currently typed on Popover */ }
<Popover.Slot name={ slotName } />
<Iframe
style={ {
width: '100%',
height: '400px',
border: '0',
outline: '1px solid purple',
} }
>
<div
style={ {
height: '200vh',
paddingTop: '10vh',
} }
>
<p
style={ {
padding: '8px',
background: 'salmon',
maxWidth: '200px',
marginTop: '100px',
marginLeft: 'auto',
marginRight: 'auto',
} }
ref={ anchorRef }
>
Popover&apos;s anchor
</p>
<Popover
{ ...args }
__unstableSlotName={ slotName }
anchorRef={ anchorRef }
/>
</div>
</Iframe>
</div>
</SlotFillProvider>
);
return <PopoverInsideIframeRenderedInExternalSlot { ...args } />;
};
WithSlotOutsideIframe.args = {
...Default.args,
Expand Down
14 changes: 14 additions & 0 deletions packages/components/src/popover/test/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
} from '../utils';
import Popover from '..';
import type { PopoverProps } from '../types';
import { PopoverInsideIframeRenderedInExternalSlot } from './utils';

type PositionToPlacementTuple = [
NonNullable< PopoverProps[ 'position' ] >,
Expand Down Expand Up @@ -175,6 +176,19 @@ describe( 'Popover', () => {
} );
} );

describe( 'Slot outside iframe', () => {
it( 'should support cross-document rendering', async () => {
render(
<PopoverInsideIframeRenderedInExternalSlot>
<span>content</span>
</PopoverInsideIframeRenderedInExternalSlot>
);
await waitFor( async () =>
expect( screen.getByText( 'content' ) ).toBeVisible()
);
} );
} );

describe( 'positionToPlacement', () => {
it.each( ALL_POSITIONS_TO_EXPECTED_PLACEMENTS )(
'converts `%s` to `%s`',
Expand Down
87 changes: 87 additions & 0 deletions packages/components/src/popover/test/utils/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/**
* WordPress dependencies
*/
import { createPortal, useState } from '@wordpress/element';

/**
* Internal dependencies
*/
import Popover from '../..';
import { Provider as SlotFillProvider } from '../../../slot-fill';
import type { WordPressComponentProps } from '../../../ui/context';

const GenericIframe = ( {
children,
...props
}: WordPressComponentProps< { children: React.ReactNode }, 'iframe' > ) => {
const [ containerNode, setContainerNode ] = useState< HTMLElement >();

return (
<iframe
{ ...props }
title="My Iframe"
srcDoc="<!doctype html><html><body></body></html>"
// Waiting for the load event ensures that this works in Firefox.
// See https://github.com/facebook/react/issues/22847#issuecomment-991394558
onLoad={ ( event ) => {
if ( event.currentTarget.contentDocument ) {
setContainerNode(
event.currentTarget.contentDocument.body
);
}
} }
>
{ containerNode && createPortal( children, containerNode ) }
</iframe>
);
};

export const PopoverInsideIframeRenderedInExternalSlot = (
props: React.ComponentProps< typeof Popover >
) => {
const SLOT_NAME = 'my-slot';
const [ anchorRef, setAnchorRef ] = useState< HTMLParagraphElement | null >(
null
);

return (
<SlotFillProvider>
{ /* @ts-expect-error Slot is not currently typed on Popover */ }
<Popover.Slot name={ SLOT_NAME } />
<GenericIframe
style={ {
width: '100%',
height: '400px',
border: '0',
outline: '1px solid purple',
} }
>
<div
style={ {
height: '200vh',
paddingTop: '10vh',
} }
>
<p
style={ {
padding: '8px',
background: 'salmon',
maxWidth: '200px',
marginTop: '100px',
marginLeft: 'auto',
marginRight: 'auto',
} }
ref={ setAnchorRef }
>
Popover&apos;s anchor
</p>
<Popover
{ ...props }
__unstableSlotName={ SLOT_NAME }
anchor={ anchorRef }
/>
</div>
</GenericIframe>
</SlotFillProvider>
);
};

0 comments on commit 054344c

Please sign in to comment.