Skip to content

Commit

Permalink
feat(Tabs): allow dismissable tabs to have descriptive icons (#13830)
Browse files Browse the repository at this point in the history
* feat(Tabs): allow dismissable tabs to have descriptive icons

* fix(Tabs): default contained ctrl to true in dismissable tabs w. icons

* fix(Tabs): remove temporary contained control

---------

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
francinelucca and kodiakhq[bot] authored Jun 1, 2023
1 parent 4943209 commit ad1031b
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 10 deletions.
8 changes: 8 additions & 0 deletions e2e/components/Tabs/Tabs-test.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ test.describe('Tabs', () => {
});
});

test('dismissable with icons @vrt', async ({ page }) => {
await snapshotStory(page, {
component: 'Tabs',
id: 'components-tabs--dismissable-with-icons',
theme,
});
});

test('manual @vrt', async ({ page }) => {
await snapshotStory(page, {
component: 'Tabs',
Expand Down
44 changes: 34 additions & 10 deletions packages/react/src/components/Tabs/Tabs-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ describe('Tab', () => {
</TabPanels>
</Tabs>
);
// eslint-disable-next-line testing-library/no-node-access
expect(screen.queryByText('test-secondary-label')).not.toBeInTheDocument();
});

Expand Down Expand Up @@ -272,10 +273,9 @@ describe('Tab', () => {
</Tabs>
);

expect(
// eslint-disable-next-line testing-library/no-node-access
screen.queryAllByLabelText('Close tab')[0].parentElement
).toHaveClass(`${prefix}--visually-hidden`);
expect(screen.queryAllByLabelText('Close tab')[0]).toHaveClass(
`${prefix}--visually-hidden`
);
});

it('should call onCloseTabRequest when dismissable and close icon clicked', async () => {
Expand Down Expand Up @@ -388,7 +388,28 @@ describe('Tab', () => {
}
});

it('should render close icon instead of renderIcon when dismissable', () => {
it('should render close icon when dismissable', () => {
render(
<Tabs dismissable>
<TabList aria-label="List of tabs">
<Tab>Tab Label 1</Tab>
<Tab>Tab Label 2</Tab>
<Tab>Tab Label 3</Tab>
</TabList>
<TabPanels>
<TabPanel>Tab Panel 1</TabPanel>
<TabPanel>Tab Panel 2</TabPanel>
<TabPanel>Tab Panel 3</TabPanel>
</TabPanels>
</Tabs>
);

expect(screen.getAllByLabelText('Close tab')[0]).not.toHaveClass(
`${prefix}--visaully-hidden`
);
});

it('should render close icon and renderIcon when dismissable and icon supplied', () => {
render(
<Tabs dismissable>
<TabList aria-label="List of tabs">
Expand All @@ -404,11 +425,14 @@ describe('Tab', () => {
</Tabs>
);

expect(
// eslint-disable-next-line testing-library/no-node-access
screen.getAllByLabelText('Close tab')[0].parentElement
).not.toHaveClass(`${prefix}--visaully-hidden`);
expect(screen.queryByTestId('svg')).not.toBeInTheDocument();
expect(screen.getAllByLabelText('Close tab')[0]).not.toHaveClass(
`${prefix}--visaully-hidden`
);
expect(screen.getByTestId('svg')).toBeInTheDocument();
// eslint-disable-next-line testing-library/no-node-access
expect(screen.getByTestId('svg').parentElement).toHaveClass(
`${prefix}--tabs__nav-item--icon-left`
);
});
});

Expand Down
5 changes: 5 additions & 0 deletions packages/react/src/components/Tabs/Tabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,11 @@ const Tab = React.forwardRef(function Tab(
tabIndex={selectedIndex === index ? '0' : '-1'}
type="button">
<div className={`${prefix}--tabs__nav-item-label-wrapper`}>
{dismissable && Icon && (
<div className={`${prefix}--tabs__nav-item--icon-left`}>
{<Icon size={16} />}
</div>
)}
<span className={`${prefix}--tabs__nav-item-label`}>{children}</span>
{/* always rendering dismissIcon so we don't lose reference to it, otherwise events do not work when switching from/to dismissable state */}
<div
Expand Down
70 changes: 70 additions & 0 deletions packages/react/src/components/Tabs/Tabs.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,76 @@ export const Dismissable = () => {
);
};

export const DismissableWithIcons = ({ contained }) => {
const tabs = [
{
label: 'Tab label 1',
panel: <TabPanel>Tab Panel 1</TabPanel>,
},
{
label: 'Tab label 2',
panel: <TabPanel>Tab Panel 2</TabPanel>,
},
{
label: 'Tab label 3',
panel: <TabPanel>Tab Panel 3</TabPanel>,
disabled: true,
},
{
label: 'Tab label 4',
panel: <TabPanel>Tab Panel 4</TabPanel>,
},
];
const [renderedTabs, setRenderedTabs] = useState(tabs);

const [selectedIndex, setSelectedIndex] = useState(0);

const handleTabChange = (evt) => {
setSelectedIndex(evt.selectedIndex);
};

const handleCloseTabRequest = (tabIndex) => {
const selectedTab = renderedTabs[selectedIndex];

const filteredTabs = renderedTabs.filter((_, index) => index !== tabIndex);
if (tabIndex === selectedIndex) {
const defaultTabIndex = filteredTabs.findIndex((tab) => !tab.disabled);
setSelectedIndex(defaultTabIndex);
} else {
setSelectedIndex(filteredTabs.indexOf(selectedTab));
}
setRenderedTabs(filteredTabs);
};

const resetTabs = () => {
setRenderedTabs(tabs);
};

const icons = [Bat, Bee, Corn, Monster];

return (
<>
<Button style={{ marginBottom: '3rem' }} onClick={resetTabs}>
Reset
</Button>
<Tabs
selectedIndex={selectedIndex}
onChange={handleTabChange}
dismissable
onTabCloseRequest={handleCloseTabRequest}>
<TabList aria-label="List of tabs" contained={contained}>
{renderedTabs.map((tab, index) => (
<Tab key={index} disabled={tab.disabled} renderIcon={icons[index]}>
{tab.label}
</Tab>
))}
</TabList>
<TabPanels>{renderedTabs.map((tab) => tab.panel)}</TabPanels>
</Tabs>
</>
);
};

export const WithIcons = () => (
<Tabs>
<TabList activation="manual" aria-label="List of tabs">
Expand Down
7 changes: 7 additions & 0 deletions packages/styles/scss/components/tabs/_tabs.scss
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,13 @@ $icon-tab-size: custom-property.get-var('icon-tab-size', rem(40px));
}
}

.#{$prefix}--tabs__nav-item--icon-left {
display: flex;
align-items: center;
padding-right: $spacing-03;
margin-top: -2px;
}

&.#{$prefix}--tabs--contained .#{$prefix}--tabs__nav-item--icon {
padding-left: $spacing-05;
}
Expand Down

0 comments on commit ad1031b

Please sign in to comment.