From 994b40f96223e67fa5a359146b437c76e00ed279 Mon Sep 17 00:00:00 2001 From: cchaos Date: Wed, 19 Jun 2019 14:34:25 -0400 Subject: [PATCH 1/3] Added `autoFocus` option to `EuiTabbedContent` --- src-docs/src/views/tabs/tabbed_content.js | 1 + .../date_popover/date_popover_content.js | 1 + src/components/tabs/index.d.ts | 3 ++ .../__snapshots__/tabbed_content.test.js.snap | 6 ++- .../tabs/tabbed_content/tabbed_content.js | 52 +++++++++++++++++-- 5 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src-docs/src/views/tabs/tabbed_content.js b/src-docs/src/views/tabs/tabbed_content.js index b54f309d519..acb7746c754 100644 --- a/src-docs/src/views/tabs/tabbed_content.js +++ b/src-docs/src/views/tabs/tabbed_content.js @@ -91,6 +91,7 @@ class EuiTabsExample extends Component { { console.log('clicked tab', tab); }} diff --git a/src/components/date_picker/super_date_picker/date_popover/date_popover_content.js b/src/components/date_picker/super_date_picker/date_popover/date_popover_content.js index a6ed6026fad..79629bd5323 100644 --- a/src/components/date_picker/super_date_picker/date_popover/date_popover_content.js +++ b/src/components/date_picker/super_date_picker/date_popover/date_popover_content.js @@ -91,6 +91,7 @@ export function EuiDatePopoverContent({ void; @@ -37,6 +39,7 @@ declare module '@elastic/eui' { size?: TAB_SIZES; display?: TAB_DISPLAYS; expand?: boolean; + autoFocus?: TABBED_CONTENT_AUTOFOCUS; } export const EuiTab: FunctionComponent< diff --git a/src/components/tabs/tabbed_content/__snapshots__/tabbed_content.test.js.snap b/src/components/tabs/tabbed_content/__snapshots__/tabbed_content.test.js.snap index e0d0cd2da8a..2fc0b3a4124 100644 --- a/src/components/tabs/tabbed_content/__snapshots__/tabbed_content.test.js.snap +++ b/src/components/tabs/tabbed_content/__snapshots__/tabbed_content.test.js.snap @@ -50,6 +50,7 @@ exports[`EuiTabbedContent behavior when selected tab state isn't controlled by t exports[`EuiTabbedContent behavior when uncontrolled, the selected tab should update if it receives new content 1`] = ` -
+
{ + console.log('THE FOCUS HAPPENED'); + + if (!this.state.inFocus && this.props.autoFocus === 'selected') { + console.log('Focusing selected tab'); + document.getElementById(this.state.selectedTabId).focus(); + } + + this.setState({ + inFocus: true, + }); + }; + + removeFocus = () => { + console.log('THE BLUR HAPPENED'); + + this.setState({ + // inFocus: false, + }); + }; + onTabClick = selectedTab => { const { onTabClick, selectedTab: externalSelectedTab } = this.props; @@ -82,6 +115,7 @@ export class EuiTabbedContent extends Component { selectedTab: externalSelectedTab, size, tabs, + autoFocus, ...rest } = this.props; @@ -93,7 +127,11 @@ export class EuiTabbedContent extends Component { const { content: selectedTabContent, id: selectedTabId } = selectedTab; return ( -
+
{tabs.map(tab => { const { @@ -125,3 +163,7 @@ export class EuiTabbedContent extends Component { ); } } + +EuiTabbedContent.defaultProps = { + autoFocus: 'initial', +}; From 68ca9b109a5c21a57dfcb8c3784617f8504dfadc Mon Sep 17 00:00:00 2001 From: Chandler Prall Date: Wed, 19 Jun 2019 13:45:01 -0600 Subject: [PATCH 2/3] Track focus & blurring across child tabs --- .../tabs/tabbed_content/tabbed_content.js | 50 ++++++++++++------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/src/components/tabs/tabbed_content/tabbed_content.js b/src/components/tabs/tabbed_content/tabbed_content.js index 2e1ce89d6a5..31511e64343 100644 --- a/src/components/tabs/tabbed_content/tabbed_content.js +++ b/src/components/tabs/tabbed_content/tabbed_content.js @@ -1,4 +1,4 @@ -import React, { Component } from 'react'; +import React, { Component, createRef } from 'react'; import PropTypes from 'prop-types'; import { htmlIdGenerator } from '../../../services'; @@ -57,6 +57,7 @@ export class EuiTabbedContent extends Component { const { initialSelectedTab, selectedTab, tabs } = props; this.rootId = makeId(); + this.divRef = createRef(); // Only track selection state if it's not controlled externally. let selectedTabId; @@ -71,25 +72,40 @@ export class EuiTabbedContent extends Component { }; } - initializeFocus = () => { - console.log('THE FOCUS HAPPENED'); + componentDidMount() { + // IE11 doesn't support the `relatedTarget` event property for blur events + // but does add it for focusout. React doesn't support `onFocusOut` so here we are. + if (this.divRef.current) { + this.divRef.current.addEventListener('focusout', this.removeFocus); + } + } - if (!this.state.inFocus && this.props.autoFocus === 'selected') { - console.log('Focusing selected tab'); - document.getElementById(this.state.selectedTabId).focus(); + componentWillUnmount() { + if (this.divRef.current) { + this.divRef.current.removeEventListener('focusout', this.removeFocus); } + } - this.setState({ - inFocus: true, - }); + initializeFocus = () => { + if (!this.state.inFocus && this.props.autoFocus === 'selected') { + // Must wait for setState to finish before calling `.focus()` + // as the focus call triggers a blur on the first tab + this.setState({ inFocus: true }, () => { + const targetTab = this.divRef.current.querySelector( + `#${this.state.selectedTabId}` + ); + targetTab.focus(); + }); + } }; - removeFocus = () => { - console.log('THE BLUR HAPPENED'); - - this.setState({ - // inFocus: false, - }); + removeFocus = blurEvent => { + // only set inFocus to false if the wrapping div doesn't contain the now-focusing element + if (blurEvent.currentTarget.contains(blurEvent.relatedTarget) === false) { + this.setState({ + inFocus: false, + }); + } }; onTabClick = selectedTab => { @@ -128,10 +144,10 @@ export class EuiTabbedContent extends Component { return (
+ onFocus={this.initializeFocus}> {tabs.map(tab => { const { From 5ae884b9a50907da584570956f535f1fd80f45e1 Mon Sep 17 00:00:00 2001 From: cchaos Date: Wed, 19 Jun 2019 16:18:41 -0400 Subject: [PATCH 3/3] Added test and CL --- CHANGELOG.md | 1 + .../__snapshots__/tabbed_content.test.js.snap | 97 ++++++++++++++++++- .../tabs/tabbed_content/tabbed_content.js | 2 +- .../tabbed_content/tabbed_content.test.js | 14 ++- 4 files changed, 111 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bf70dc2589..96c98499f47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - Changed `EuiNavDrawerFlyout` title from `h5` to `div` ([#2040](https://github.com/elastic/eui/pull/2040)) - Added `magnifyWithMinus` and `magnifyWithPlus` glyphs to `EuiIcon` ([2056](https://github.com/elastic/eui/pull/2056)) - Added a fully black (no matter the theme) color SASS variable `$euiColorInk` ([2060](https://github.com/elastic/eui/pull/2060)) +- Added `autoFocus` prop to `EuiTabbedContent` ([2062](https://github.com/elastic/eui/pull/2062)) **Bug fixes** diff --git a/src/components/tabs/tabbed_content/__snapshots__/tabbed_content.test.js.snap b/src/components/tabs/tabbed_content/__snapshots__/tabbed_content.test.js.snap index 2fc0b3a4124..c2c0ef74cbe 100644 --- a/src/components/tabs/tabbed_content/__snapshots__/tabbed_content.test.js.snap +++ b/src/components/tabs/tabbed_content/__snapshots__/tabbed_content.test.js.snap @@ -72,7 +72,6 @@ exports[`EuiTabbedContent behavior when uncontrolled, the selected tab should up } >
`; +exports[`EuiTabbedContent props autoFocus initial is rendered 1`] = ` +
+
+ + +
+
+

+ Elasticsearch content +

+
+
+`; + +exports[`EuiTabbedContent props autoFocus selected is rendered 1`] = ` +
+
+ + +
+
+

+ Elasticsearch content +

+
+
+`; + exports[`EuiTabbedContent props display can be condensed 1`] = `
({ @@ -81,6 +81,18 @@ describe('EuiTabbedContent', () => { expect(component).toMatchSnapshot(); }); }); + + describe('autoFocus', () => { + AUTOFOCUS.forEach(focusType => { + test(`${focusType} is rendered`, () => { + const component = render( + + ); + + expect(component).toMatchSnapshot(); + }); + }); + }); }); describe('behavior', () => {