diff --git a/blocks/library/embed/index.js b/blocks/library/embed/index.js index 5b0c80628e6f27..51f8e7c2d94d2c 100644 --- a/blocks/library/embed/index.js +++ b/blocks/library/embed/index.js @@ -71,7 +71,9 @@ function getEmbedBlockSettings( { title, icon, category = 'embed', transforms, k edit: class extends Component { constructor() { super( ...arguments ); + this.doServerSideRender = this.doServerSideRender.bind( this ); + this.state = { html: '', type: '', diff --git a/components/focusable-iframe/README.md b/components/focusable-iframe/README.md new file mode 100644 index 00000000000000..b1b09a74974a01 --- /dev/null +++ b/components/focusable-iframe/README.md @@ -0,0 +1,39 @@ +Focusable Iframe +================ + +`` is a component rendering an `iframe` element enhanced to support focus events. By default, it is not possible to detect when an iframe is focused or clicked within. This enhanced component uses a technique which checks whether the target of a window `blur` event is the iframe, inferring that this has resulted in the focus of the iframe. It dispatches an emulated [`FocusEvent`](https://developer.mozilla.org/en-US/docs/Web/API/FocusEvent) on the iframe element with event bubbling, so a parent component binding its own `onFocus` event will account for focus transitioning within the iframe. + +## Usage + +Use as you would a standard `iframe`. You may pass `onFocus` directly as the callback to be invoked when the iframe receives focus, or on an ancestor component since the event will bubble. + +```jsx +import { FocusableIframe } from '@wordpress/components'; + +function MyIframe() { + return ( + + ); +} +``` + +## Props + +Any props aside from those listed below will be passed to the `FocusableIframe` will be passed through to the underlying `iframe` element. + +### `onFocus` + +- Type: `Function` +- Required: No + +Callback to invoke when iframe receives focus. Passes an emulated `FocusEvent` object as the first argument. + +### `iframeRef` + +- Type: `wp.element.Ref` +- Required: No + +If a reference to the underlying DOM element is needed, pass `iframeRef` as the result of a `wp.element.createRef` called from your component. diff --git a/components/focusable-iframe/index.js b/components/focusable-iframe/index.js new file mode 100644 index 00000000000000..2d6a1a2b177655 --- /dev/null +++ b/components/focusable-iframe/index.js @@ -0,0 +1,69 @@ +/** + * External dependencies + */ +import { omit } from 'lodash'; + +/** + * WordPress dependencies + */ +import { Component, createRef } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import withGlobalEvents from '../higher-order/with-global-events'; + +/** + * Browser dependencies + */ + +const { FocusEvent } = window; + +class FocusableIframe extends Component { + constructor( props ) { + super( ...arguments ); + + this.checkFocus = this.checkFocus.bind( this ); + + this.node = props.iframeRef || createRef(); + } + + /** + * Checks whether the iframe is the activeElement, inferring that it has + * then received focus, and calls the `onFocus` prop callback. + */ + checkFocus() { + const iframe = this.node.current; + + if ( document.activeElement !== iframe ) { + return; + } + + const focusEvent = new FocusEvent( 'focus', { bubbles: true } ); + iframe.dispatchEvent( focusEvent ); + + const { onFocus } = this.props; + if ( onFocus ) { + onFocus( focusEvent ); + } + } + + render() { + // Disable reason: The rendered iframe is a pass-through component, + // assigning props inherited from the rendering parent. It's the + // responsibility of the parent to assign a title. + + /* eslint-disable jsx-a11y/iframe-has-title */ + return ( +