From 302f25d7d14670af0de9d9cec486fd8968ed75ff Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Fri, 5 Apr 2019 15:37:05 -0400 Subject: [PATCH] Components: Add onFocusOutside alternative to Popover onClickOutside --- lib/packages-dependencies.php | 1 + package-lock.json | 1 + packages/components/CHANGELOG.md | 7 ++- packages/components/package.json | 1 + packages/components/src/popover/README.md | 6 ++- .../components/src/popover/detect-outside.js | 17 +++---- packages/components/src/popover/index.js | 48 ++++++++++++++++++- .../popover/test/__snapshots__/index.js.snap | 34 +++++++------ 8 files changed, 85 insertions(+), 30 deletions(-) diff --git a/lib/packages-dependencies.php b/lib/packages-dependencies.php index 3bfbecc382c490..50941bb71e665e 100644 --- a/lib/packages-dependencies.php +++ b/lib/packages-dependencies.php @@ -86,6 +86,7 @@ 'wp-a11y', 'wp-api-fetch', 'wp-compose', + 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-hooks', diff --git a/package-lock.json b/package-lock.json index 0d2eebacd8c20f..73b28d4a849ad1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2707,6 +2707,7 @@ "@wordpress/a11y": "file:packages/a11y", "@wordpress/api-fetch": "file:packages/api-fetch", "@wordpress/compose": "file:packages/compose", + "@wordpress/deprecated": "file:packages/deprecated", "@wordpress/dom": "file:packages/dom", "@wordpress/element": "file:packages/element", "@wordpress/hooks": "file:packages/hooks", diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index ee616f4404f151..579eb543a527a4 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -1,15 +1,20 @@ -## 7.3.0 (Unreleased) +## Unreleased ### New Features - Added a new `render` property to `FormFileUpload` component. Allowing users of the component to custom the UI for their needs. - Added a new `BaseControl.VisualLabel` component. - Added a new `preview` prop to the `Placeholder` component which allows to display a preview, for example a media preview when the Placeholder is used in media editing contexts. +- Added a new `onFocusOutside` prop to the `Popover` component which serves in place of the existing `onClickOutside` to more accurately reflect all causes for focus transition. ### Bug fixes - Fix `instanceId` prop passed through to `Button` component via `MenuItems` producing React console error. Fixed by removing the unnecessary use of `withInstanceId` on the `MenuItems` component [#14599](https://github.com/WordPress/gutenberg/pull/14599) +### Deprecations + +- The `Popover` component `onClickOutside` prop has been deprecated. Use `onFocusOutside` instead. + ## 7.2.0 (2019-03-20) ### Improvements diff --git a/packages/components/package.json b/packages/components/package.json index 71c5a2a21ccc11..72cb4a1ba23fe6 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -25,6 +25,7 @@ "@wordpress/a11y": "file:../a11y", "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/compose": "file:../compose", + "@wordpress/deprecated": "file:../deprecated", "@wordpress/dom": "file:../dom", "@wordpress/element": "file:../element", "@wordpress/hooks": "file:../hooks", diff --git a/packages/components/src/popover/README.md b/packages/components/src/popover/README.md index f071dbcad2a645..6bc3471f38f083 100644 --- a/packages/components/src/popover/README.md +++ b/packages/components/src/popover/README.md @@ -93,9 +93,11 @@ A callback invoked when the popover should be closed. - Type: `Function` - Required: No -### onClickOutside +### onFocusOutside -A callback invoked when the user clicks outside the opened popover, passing the click event. The popover should be closed in response to this interaction. Defaults to `onClose`. +A callback invoked when the focus leaves the opened popover. This should only be provided in advanced use-cases when a Popover should close under specific circumstances; for example, if the new `document.activeElement` is content of or otherwise controlling Popover visibility. + +Defaults to `onClose` when not provided. - Type: `Function` - Required: No diff --git a/packages/components/src/popover/detect-outside.js b/packages/components/src/popover/detect-outside.js index a890eb664fcacc..92a3359d24055f 100644 --- a/packages/components/src/popover/detect-outside.js +++ b/packages/components/src/popover/detect-outside.js @@ -1,19 +1,16 @@ /** - * External dependencies + * WordPress dependencies */ -import clickOutside from 'react-click-outside'; +import { Component } from '@wordpress/element'; /** - * WordPress dependencies + * Internal dependencies */ -import { Component } from '@wordpress/element'; +import withFocusOutside from '../higher-order/with-focus-outside'; class PopoverDetectOutside extends Component { - handleClickOutside( event ) { - const { onClickOutside } = this.props; - if ( onClickOutside ) { - onClickOutside( event ); - } + handleFocusOutside( event ) { + this.props.onFocusOutside( event ); } render() { @@ -21,4 +18,4 @@ class PopoverDetectOutside extends Component { } } -export default clickOutside( PopoverDetectOutside ); +export default withFocusOutside( PopoverDetectOutside ); diff --git a/packages/components/src/popover/index.js b/packages/components/src/popover/index.js index 47212a3e12f9ca..26ac7831a20257 100644 --- a/packages/components/src/popover/index.js +++ b/packages/components/src/popover/index.js @@ -10,6 +10,7 @@ import { Component, createRef } from '@wordpress/element'; import { focus } from '@wordpress/dom'; import { ESCAPE } from '@wordpress/keycodes'; import isShallowEqual from '@wordpress/is-shallow-equal'; +import deprecated from '@wordpress/deprecated'; /** * Internal dependencies @@ -40,6 +41,7 @@ class Popover extends Component { this.getAnchorRect = this.getAnchorRect.bind( this ); this.computePopoverPosition = this.computePopoverPosition.bind( this ); this.maybeClose = this.maybeClose.bind( this ); + this.onFocusOutside = this.onFocusOutside.bind( this ); this.throttledRefresh = this.throttledRefresh.bind( this ); this.refresh = this.refresh.bind( this ); this.refreshOnAnchorMove = this.refreshOnAnchorMove.bind( this ); @@ -94,6 +96,47 @@ class Popover extends Component { this.toggleAutoRefresh( false ); } + /** + * Shims an onFocusOutside callback to be compatible with a deprecated + * onClickOutside prop function, if provided. + * + * @param {FocusEvent} event Focus event from onFocusOutside. + */ + onFocusOutside( event ) { + const { onClickOutside, onFocusOutside, onClose } = this.props; + + // Defer to given `onFocusOutside` if specified. Call `onClose` only if + // both `onFocusOutside` and `onClickOutside` are unspecified. Doing so + // assures backwards-compatibility for prior `onClickOutside` default. + if ( onFocusOutside ) { + onFocusOutside( event ); + return; + } else if ( ! onClickOutside ) { + onClose(); + return; + } + + // Simulate MouseEvent using FocusEvent#relatedTarget as emulated click + // target. MouseEvent constructor is unsupported in Internet Explorer. + let clickEvent; + try { + clickEvent = new window.MouseEvent( 'click' ); + } catch ( error ) { + clickEvent = document.createEvent( 'MouseEvent' ); + clickEvent.initMouseEvent( 'click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null ); + } + + Object.defineProperty( clickEvent, 'target', { + get: () => event.relatedTarget, + } ); + + deprecated( 'Popover onClickOutside prop', { + alternative: 'onFocusOutside', + } ); + + onClickOutside( clickEvent ); + } + toggleAutoRefresh( isActive ) { window.cancelAnimationFrame( this.rafHandle ); @@ -254,7 +297,6 @@ class Popover extends Component { onClose, children, className, - onClickOutside = onClose, noArrow, // Disable reason: We generate the `...contentProps` rest as remainder // of props which aren't explicitly handled by this component. @@ -265,6 +307,8 @@ class Popover extends Component { getAnchorRect, expandOnMobile, animate = true, + onClickOutside, + onFocusOutside, /* eslint-enable no-unused-vars */ ...contentProps } = this.props; @@ -308,7 +352,7 @@ class Popover extends Component { /* eslint-disable jsx-a11y/no-static-element-interactions */ let content = ( - +
- @@ -29,15 +31,17 @@ exports[`Popover #render() should render content 1`] = ` tabindex="-1" >
-
+
- Hello +
+ Hello +