Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Tab): make tab functional component #9722

Merged
merged 27 commits into from
Oct 19, 2021
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
2cdacc8
feat(Tab): make tab functional component
jnm2377 Sep 22, 2021
be88f6a
feat(Tabs): convert to functional
jnm2377 Oct 1, 2021
e59a53e
Merge branch 'main' of github.com:carbon-design-system/carbon into cl…
jnm2377 Oct 1, 2021
6d9e103
fix: remove console.logs
jnm2377 Oct 4, 2021
762860d
fix: export components as default
jnm2377 Oct 4, 2021
4940785
Merge branch 'main' of github.com:carbon-design-system/carbon into cl…
jnm2377 Oct 4, 2021
b9d0e43
fix: tabs state and refs
jnm2377 Oct 4, 2021
047a141
fix: use prefix
jnm2377 Oct 5, 2021
de12b3a
fix: add feature flag v11 story
jnm2377 Oct 5, 2021
19aaa75
fix: temp use v10 classNames
jnm2377 Oct 6, 2021
0442bd7
fix: clean up, comment, and fix select
jnm2377 Oct 6, 2021
d52043e
fix: keyboard navigation
jnm2377 Oct 6, 2021
dec0a57
fix: remove console log
jnm2377 Oct 6, 2021
9917fd2
chore: tabs comment
jnm2377 Oct 11, 2021
22849a8
feat: add tab tests
jnm2377 Oct 11, 2021
024a47e
feat: add tabs tests
jnm2377 Oct 13, 2021
f10bda4
fix: add back light
jnm2377 Oct 13, 2021
0ef6abd
fix: remove v11 styles
jnm2377 Oct 13, 2021
5ec774a
Merge branch 'main' into class-to-function/tabs
jnm2377 Oct 18, 2021
a5d0e65
Update packages/react/src/components/Tabs/index.js
jnm2377 Oct 18, 2021
e7ab851
fix: next tab test and deprecation
jnm2377 Oct 18, 2021
730f9d8
fix: tabs deprecate unused props
jnm2377 Oct 18, 2021
06c4a5d
Merge branch 'class-to-function/tabs' of github.com:jnm2377/carbon in…
jnm2377 Oct 18, 2021
2e8925f
fix: deprecations'
jnm2377 Oct 18, 2021
6be4cb3
fix: tab role presentation test
jnm2377 Oct 18, 2021
aa706cc
fix: remove unused arg'
jnm2377 Oct 19, 2021
009724f
Merge branch 'main' into class-to-function/tabs
kodiakhq[bot] Oct 19, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions packages/carbon-react/src/components/Tabs/Tabs.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,18 @@

import React from 'react';
import { Button, Tab, Tabs, TabsSkeleton } from '../Tabs';
import { unstable_FeatureFlags as FeatureFlags } from 'carbon-components-react';
import { Layer } from '../Layer';

export default {
title: 'Components/Tabs',
decorators: [
(Story) => (
<FeatureFlags flags={{ 'enable-v11-release': true }}>
<Story />
</FeatureFlags>
),
],
parameters: {
component: Tabs,
subcomponents: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5905,7 +5905,6 @@ Map {
"label": "provide a label",
"onClick": [Function],
"onKeyDown": [Function],
"role": "presentation",
"selected": false,
},
"propTypes": Object {
Expand Down Expand Up @@ -5946,10 +5945,7 @@ Map {
"renderContent": Object {
"type": "func",
},
"role": Object {
"isRequired": true,
"type": "string",
},
"role": [Function],
"selected": Object {
"isRequired": true,
"type": "bool",
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/components/Tab/Tab-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe('Tab', () => {
});

it('renders <li> with [role="presentation"]', () => {
expect(wrapper.props().role).toEqual('presentation');
expect(wrapper.find('li').prop('role')).toEqual('presentation');
});

it('renders <button> with tabindex set to 0', () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/react/src/components/Tab/Tab.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export default class Tab extends React.Component {
/**
* Provide an accessibility role for your Tab
*/
role: PropTypes.string.isRequired,
role: deprecate(PropTypes.string),
tay1orjones marked this conversation as resolved.
Show resolved Hide resolved

/**
* Whether your Tab is selected.
Expand All @@ -97,7 +97,6 @@ export default class Tab extends React.Component {
};

static defaultProps = {
role: 'presentation',
label: 'provide a label',
selected: false,
onClick: () => {},
Expand All @@ -122,6 +121,7 @@ export default class Tab extends React.Component {
renderAnchor,
renderButton,
renderContent, // eslint-disable-line no-unused-vars
role, // eslint-disable-line no-unused-vars
...other
} = this.props;

Expand Down
8 changes: 7 additions & 1 deletion packages/react/src/components/Tab/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,10 @@
* LICENSE file in the root directory of this source tree.
*/

export default from './Tab';
import * as FeatureFlags from '@carbon/feature-flags';
import { default as TabNext } from './next/Tab';
import { default as TabClassic } from './Tab';

const Tab = FeatureFlags.enabled('enable-v11-release') ? TabNext : TabClassic;

export default Tab;
204 changes: 204 additions & 0 deletions packages/react/src/components/Tab/next/Tab-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
import React from 'react';
import { default as Tab } from './Tab';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

describe('Tab', () => {
it('adds extra classes that are passed via className', async () => {
render(
<Tab
className="custom-class"
label="Tab 1"
onClick={() => {}}
onKeyDown={() => {}}
selected={false}>
<p>Content for first tab goes here.</p>
</Tab>
);

await expect(
screen.getByRole('presentation').classList.contains('custom-class')
).toBe(true);
});

it('sets tabIndex on <button> if one is passed via props', async () => {
render(
<Tab
label="Tab 1"
// eslint-disable-next-line jsx-a11y/tabindex-no-positive
tabIndex={2}
onClick={() => {}}
onKeyDown={() => {}}
selected={false}>
<p>Content for first tab goes here.</p>
</Tab>
);

await expect(screen.getByRole('tab').tabIndex).toEqual(2);
});

it('renders <li> with [role="presentation"]', async () => {
render(
<Tab
className="custom-class"
label="Tab 1"
onClick={() => {}}
onKeyDown={() => {}}
selected={false}>
<p>Content for first tab goes here.</p>
</Tab>
);

await expect(screen.getByRole('presentation')).toBeTruthy();
});

it('renders <button> with tabindex set to 0 by default', async () => {
render(
<Tab
label="Tab 1"
onClick={() => {}}
onKeyDown={() => {}}
selected={false}>
<p>Content for first tab goes here.</p>
</Tab>
);

await expect(screen.getByRole('tab').tabIndex).toEqual(0);
});

it('renders <button> with tabindex set to -1 if disabled', async () => {
render(
<Tab
label="Tab 1"
onClick={() => {}}
onKeyDown={() => {}}
selected={false}
disabled>
<p>Content for first tab goes here.</p>
</Tab>
);

await expect(screen.getByRole('tab').tabIndex).toEqual(-1);
});

it('uses label to set children on <button> when passed via props', async () => {
render(
<Tab
label="Tab 1"
onClick={() => {}}
onKeyDown={() => {}}
selected={false}>
<p>Content for first tab goes here.</p>
</Tab>
);

await expect(screen.getByRole('tab').textContent).toBe('Tab 1');
});

it('has aria-disabled that matches disabled', async () => {
render(
<Tab
label="Tab 1"
onClick={() => {}}
onKeyDown={() => {}}
selected={false}
disabled>
<p>Content for first tab goes here.</p>
</Tab>
);

await expect(screen.getByRole('tab')).toHaveAttribute('aria-disabled');
});
});

describe('Click events', () => {
it('invokes handleTabClick from handleTabClick prop', async () => {
const handleTabClick = jest.fn();
render(
<Tab
label="Tab 1"
handleTabClick={handleTabClick}
onClick={() => {}}
onKeyDown={() => {}}
selected={false}>
<p>Content for first tab goes here.</p>
</Tab>
);

const button = screen.getByRole('tab');
userEvent.click(button);
await expect(handleTabClick).toHaveBeenCalled();
});

it('invokes onClick when a function is passed to onClick prop', async () => {
const onClick = jest.fn();

render(
<Tab
label="Tab 1"
onClick={onClick}
onKeyDown={() => {}}
selected={false}>
<p>Content for first tab goes here.</p>
</Tab>
);

const button = screen.getByRole('tab');
userEvent.click(button);
await expect(onClick).toHaveBeenCalled();
});

it('does not invoke click handler if tab is disabled', async () => {
const onClick = jest.fn();

render(
<Tab
label="Tab 1"
onClick={onClick}
onKeyDown={() => {}}
selected={false}
disabled>
<p>Content for first tab goes here.</p>
</Tab>
);

const button = screen.getByRole('tab');
userEvent.click(button);
await expect(onClick).not.toHaveBeenCalled();
});
});

describe('Keyboard events', () => {
it('invokes onKeyDown from onKeyDown prop', async () => {
const onKeyDown = jest.fn();
render(
<Tab label="Tab 1" onClick={() => {}} onKeyDown={onKeyDown} selected>
<p>Content for first tab goes here.</p>
</Tab>
);

const button = screen.getByRole('tab');
userEvent.type(button, '[ArrowLeft]');

await expect(onKeyDown).toHaveBeenCalled();
});

it('invokes handleTabKeyDown from handleTabKeyDown prop', async () => {
const handleTabKeyDown = jest.fn();
render(
<Tab
label="Tab 1"
onClick={() => {}}
onKeyDown={() => {}}
handleTabKeyDown={handleTabKeyDown}
selected>
<p>Content for first tab goes here.</p>
</Tab>
);

const button = screen.getByRole('tab');
userEvent.type(button, '[ArrowRight]');

await expect(handleTabKeyDown).toHaveBeenCalled();
});
});
Loading