diff --git a/package-lock.json b/package-lock.json index c2ed10753..0ff5c14c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20846,6 +20846,11 @@ "has-symbols": "^1.0.0" } }, + "tabbable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-4.0.0.tgz", + "integrity": "sha512-H1XoH1URcBOa/rZZWxLxHCtOdVUEev+9vo5YdYhC9tCY4wnybX+VQrCYuy9ubkg69fCBxCONJOSLGfw0DWMffQ==" + }, "table": { "version": "5.4.6", "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", diff --git a/package.json b/package.json index 8dc3010b1..b4cd68d00 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,8 @@ "react-focus-lock": "^2.1.1", "react-overlays": "^1.1.2", "react-popper": "^1.3.3", - "shortid": "^2.2.14" + "shortid": "^2.2.14", + "tabbable": "^4.0.0" }, "devDependencies": { "@babel/cli": "^7.1.5", diff --git a/src/ComboboxInput/ComboboxInput.js b/src/ComboboxInput/ComboboxInput.js index c4b47427c..980b81154 100644 --- a/src/ComboboxInput/ComboboxInput.js +++ b/src/ComboboxInput/ComboboxInput.js @@ -39,7 +39,8 @@ const ComboboxInput = React.forwardRef(({ placeholder, menu, compact, className, } disableKeyPressHandler disableStyles={disableStyles} - noArrow /> + noArrow + useArrowKeyNavigation /> ); }); diff --git a/src/Dropdown/Dropdown.Component.js b/src/Dropdown/Dropdown.Component.js index 9e36e15ca..7458c017d 100644 --- a/src/Dropdown/Dropdown.Component.js +++ b/src/Dropdown/Dropdown.Component.js @@ -28,7 +28,8 @@ export const DropdownComponent = () => { } control={} id='jhqD0555' - noArrow /> + noArrow + useArrowKeyNavigation /> @@ -49,7 +50,8 @@ export const DropdownComponent = () => { } id='jhqD0556' - noArrow /> + noArrow + useArrowKeyNavigation /> @@ -75,7 +77,8 @@ export const DropdownComponent = () => { } id='jhqD0557' - noArrow /> + noArrow + useArrowKeyNavigation /> @@ -97,7 +100,8 @@ export const DropdownComponent = () => { } id='jhqD0558' - noArrow /> + noArrow + useArrowKeyNavigation /> @@ -122,7 +126,8 @@ export const DropdownComponent = () => { } id='jhqD0559' - noArrow /> + noArrow + useArrowKeyNavigation /> @@ -143,7 +148,8 @@ export const DropdownComponent = () => { } id='jhqD0560' - noArrow /> + noArrow + useArrowKeyNavigation /> @@ -170,7 +176,8 @@ export const DropdownComponent = () => { } disabled id='jhqD0561' - noArrow /> + noArrow + useArrowKeyNavigation /> diff --git a/src/Dropdown/__stories__/Dropdown.stories.js b/src/Dropdown/__stories__/Dropdown.stories.js index eda091941..52ffa4aa5 100644 --- a/src/Dropdown/__stories__/Dropdown.stories.js +++ b/src/Dropdown/__stories__/Dropdown.stories.js @@ -25,7 +25,8 @@ storiesOf('Components|Dropdown', module) } control={} id='jhqD0555' - noArrow /> + noArrow + useArrowKeyNavigation /> )) .add('disable styles', () => ( @@ -45,7 +46,8 @@ storiesOf('Components|Dropdown', module) control={} disableStyles id='jhqD0555' - noArrow /> + noArrow + useArrowKeyNavigation /> )) .add('custom styles', () => ( @@ -65,6 +67,7 @@ storiesOf('Components|Dropdown', module) control={} disableStyles id='jhqD0555' - noArrow /> + noArrow + useArrowKeyNavigation /> )); diff --git a/src/Popover/Popover.js b/src/Popover/Popover.js index a477a8492..af80848dc 100644 --- a/src/Popover/Popover.js +++ b/src/Popover/Popover.js @@ -1,9 +1,12 @@ import chain from 'chain-function'; import classnames from 'classnames'; +import { findDOMNode } from 'react-dom'; +import FocusManager from '../utils/focusManager/focusManager'; import keycode from 'keycode'; import Popper from '../utils/_Popper'; import PropTypes from 'prop-types'; import shortId from '../utils/shortId'; +import tabbable from 'tabbable'; import withStyles from '../utils/WithStyles/WithStyles'; import { POPOVER_TYPES, POPPER_PLACEMENTS } from '../utils/constants'; import React, { Component } from 'react'; @@ -41,6 +44,12 @@ class Popover extends Component { } }; + handleFocusManager = () => { + if (this.state.isExpanded && this.popover) { + this.focusManager = new FocusManager(this.popover, this.controlRef, this.props.useArrowKeyNavigation); + } + } + handleOutsideClick = () => { if (this.state.isExpanded) { this.setState({ @@ -49,6 +58,19 @@ class Popover extends Component { } }; + handleEscapeKey = () => { + this.handleOutsideClick(); + + if (this.controlRef) { + if (tabbable.isTabbable(this.controlRef)) { + this.controlRef.focus(); + } else { + const firstTabbableNode = tabbable(this.controlRef)[0]; + firstTabbableNode && firstTabbableNode.focus(); + } + } + } + handleKeyPress = (event, node, onClickFunctions) => { if (!this.isButton(node)) { switch (keycode(event)) { @@ -76,6 +98,7 @@ class Popover extends Component { className, placement, popperProps, + useArrowKeyNavigation, type, ...rest } = this.props; @@ -88,7 +111,15 @@ class Popover extends Component { const id = popperProps.id || this.popoverId; let controlProps = { - onClick: onClickFunctions + onClick: onClickFunctions, + ref: (c) => { + this.controlRef = findDOMNode(c); + } + }; + + const innerRef = (c) => { + this.popover = findDOMNode(c); + this.handleFocusManager(); }; if (!disableKeyPressHandler) { @@ -112,9 +143,10 @@ class Popover extends Component { ( } - type='menu' /> + body={someMenu} + control={