Skip to content

Commit

Permalink
[EuiPopover] Handle initialFocus (#4768)
Browse files Browse the repository at this point in the history
* use hasSetInitialFocus

* revert me

* Revert "revert me"

This reverts commit 011ed24.

* docs

* CL
  • Loading branch information
thompsongl authored Apr 29, 2021
1 parent 8d3b471 commit 45d142b
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 8 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
## [`master`](https://github.com/elastic/eui/tree/master)

No public interface changes since `32.3.0`.
**Bug fixes**

- Fixed `initialFocus` prop functionality in `EuiPopover` ([#4768](https://github.com/elastic/eui/pull/4768))

## [`32.3.0`](https://github.com/elastic/eui/tree/v32.3.0)

Expand Down
3 changes: 2 additions & 1 deletion src-docs/src/views/form_layouts/inline_popover.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ export default () => {
id="formPopover"
button={button2}
isOpen={isPopover2Open}
closePopover={closePopover2}>
closePopover={closePopover2}
initialFocus="[name='popfirst']">
<div style={{ width: '300px' }}>{formSample2}</div>
</EuiPopover>
</div>
Expand Down
24 changes: 18 additions & 6 deletions src/components/popover/popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,10 @@ export interface EuiPopoverProps {
* node, or a selector string (which will be passed to
* document.querySelector() to find the DOM node), or a function that
* returns a DOM node
* Set to `false` to prevent initial auto-focus. Use only
* when your app handles setting initial focus state.
*/
initialFocus?: FocusTarget;
initialFocus?: FocusTarget | false;
/**
* Passed directly to EuiPortal for DOM positioning. Both properties are
* required if prop is specified
Expand Down Expand Up @@ -358,6 +360,7 @@ export class EuiPopover extends Component<Props, State> {
private updateFocusAnimationFrame: number | undefined;
private button: HTMLElement | null = null;
private panel: HTMLElement | null = null;
private hasSetInitialFocus: boolean = false;

constructor(props: Props) {
super(props);
Expand Down Expand Up @@ -408,12 +411,19 @@ export class EuiPopover extends Component<Props, State> {
updateFocus() {
// Wait for the DOM to update.
this.updateFocusAnimationFrame = window.requestAnimationFrame(() => {
if (!this.props.ownFocus || !this.panel) {
if (
!this.props.ownFocus ||
!this.panel ||
this.props.initialFocus === false
) {
return;
}

// If we've already focused on something inside the panel, everything's fine.
if (this.panel.contains(document.activeElement)) {
if (
this.hasSetInitialFocus &&
this.panel.contains(document.activeElement)
) {
return;
}

Expand Down Expand Up @@ -453,7 +463,10 @@ export class EuiPopover extends Component<Props, State> {
}
}

if (focusTarget != null) focusTarget.focus();
if (focusTarget != null) {
this.hasSetInitialFocus = true;
focusTarget.focus();
}
});
}

Expand Down Expand Up @@ -506,8 +519,6 @@ export class EuiPopover extends Component<Props, State> {
if (this.props.repositionOnScroll) {
window.addEventListener('scroll', this.positionPopoverFixed);
}

this.updateFocus();
}

componentDidUpdate(prevProps: Props) {
Expand All @@ -530,6 +541,7 @@ export class EuiPopover extends Component<Props, State> {
// If the user has just closed the popover, queue up the removal of the content after the
// transition is complete.
this.closingTransitionTimeout = window.setTimeout(() => {
this.hasSetInitialFocus = false;
this.setState({
isClosing: false,
});
Expand Down

0 comments on commit 45d142b

Please sign in to comment.