diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c6e8d7d89c..83483236913 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Converted `EuiGlobalToastList` into ARIA live region by adding `role="region"` attribute to add NVDA/JAWS support ([#2055](https://github.com/elastic/eui/pull/2055)) - 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-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..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 @@ -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`] = ` -
+
`; +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`] = `
{ + 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 = 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 => { const { onTabClick, selectedTab: externalSelectedTab } = this.props; @@ -82,6 +131,7 @@ export class EuiTabbedContent extends Component { selectedTab: externalSelectedTab, size, tabs, + autoFocus, ...rest } = this.props; @@ -93,7 +143,11 @@ export class EuiTabbedContent extends Component { const { content: selectedTabContent, id: selectedTabId } = selectedTab; return ( -
+
{tabs.map(tab => { const { @@ -125,3 +179,7 @@ export class EuiTabbedContent extends Component { ); } } + +EuiTabbedContent.defaultProps = { + autoFocus: 'initial', +}; diff --git a/src/components/tabs/tabbed_content/tabbed_content.test.js b/src/components/tabs/tabbed_content/tabbed_content.test.js index 73437815aaa..d07302919af 100644 --- a/src/components/tabs/tabbed_content/tabbed_content.test.js +++ b/src/components/tabs/tabbed_content/tabbed_content.test.js @@ -3,7 +3,7 @@ import { render, mount } from 'enzyme'; import sinon from 'sinon'; import { requiredProps, findTestSubject } from '../../../test'; -import { EuiTabbedContent } from './tabbed_content'; +import { EuiTabbedContent, AUTOFOCUS } from './tabbed_content'; // Mock the htmlIdGenerator to generate predictable ids for snapshot tests jest.mock('../../../services/accessibility/html_id_generator', () => ({ @@ -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', () => {