Skip to content

Commit b4e53fc

Browse files
committed
feat(tabs): container type supports icons
Closes #2724
1 parent b5ed9bd commit b4e53fc

File tree

9 files changed

+116
-6
lines changed

9 files changed

+116
-6
lines changed

css/_tabs.scss

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,23 @@
2727
.#{$prefix}--tabs__nav-item--disabled .#{$prefix}--tabs__nav-item--icon svg {
2828
fill: $disabled-02;
2929
}
30+
31+
.#{$prefix}--tabs--container
32+
.#{$prefix}--tabs__nav-item--disabled
33+
.#{$prefix}--tabs__nav-item--icon
34+
svg {
35+
fill: $text-on-color-disabled;
36+
}
37+
38+
.#{$prefix}--tabs--container
39+
.#{$prefix}--tabs__nav-link:has(.#{$prefix}--tabs__nav-item--icon) {
40+
inline-size: 100%;
41+
}
42+
43+
.#{$prefix}--tabs--container .#{$prefix}--tabs__nav-item--icon {
44+
margin-inline-start: auto;
45+
padding-inline-start: $carbon--spacing-05;
46+
}
3047
}
3148

3249
@include exports('tabs-icon') {

css/all.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

css/g10.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

css/g100.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

css/g80.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

css/g90.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

css/white.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<script lang="ts">
2+
import { Tab, TabContent, Tabs } from "carbon-components-svelte";
3+
import Calendar from "../../src/icons/Calendar.svelte";
4+
5+
export let icon = Calendar;
6+
export let disabled = false;
7+
export let label = "Test Tab";
8+
</script>
9+
10+
<Tabs type="container">
11+
<Tab {label} {icon} {disabled} />
12+
<Tab label="No Icon" />
13+
<svelte:fragment slot="content">
14+
<TabContent>Icon content</TabContent>
15+
<TabContent>Plain content</TabContent>
16+
</svelte:fragment>
17+
</Tabs>

tests/Tabs/Tabs.test.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Settings from "../../src/icons/Settings.svelte";
44
import { user } from "../setup-tests";
55
import Tab from "./Tab.test.svelte";
66
import TabIcon from "./TabIcon.test.svelte";
7+
import TabIconContainer from "./TabIconContainer.test.svelte";
78
import Tabs from "./Tabs.test.svelte";
89
import TabsDynamic from "./TabsDynamic.test.svelte";
910
import TabsSkeleton from "./TabsSkeleton.test.svelte";
@@ -442,6 +443,81 @@ describe("Tab icon", () => {
442443
});
443444
});
444445

446+
describe("Container tabs with icon", () => {
447+
it("should render container type with icon", () => {
448+
const { container } = render(TabIconContainer, {
449+
props: { icon: Calendar },
450+
});
451+
452+
const tabsContainer = screen.getByRole("navigation");
453+
expect(tabsContainer).toHaveClass("bx--tabs--container");
454+
455+
const iconWrapper = container.querySelector(".bx--tabs__nav-item--icon");
456+
expect(iconWrapper).toBeInTheDocument();
457+
458+
const svg = iconWrapper?.querySelector("svg");
459+
expect(svg).toBeInTheDocument();
460+
expect(svg).toHaveAttribute("width", "16");
461+
expect(svg).toHaveAttribute("height", "16");
462+
});
463+
464+
it("should not render icon wrapper on tab without icon in container", () => {
465+
const { container } = render(TabIconContainer, {
466+
props: { icon: Calendar },
467+
});
468+
469+
const navItems = container.querySelectorAll(".bx--tabs__nav-item");
470+
const secondTab = navItems[1];
471+
const iconWrapper = secondTab?.querySelector(".bx--tabs__nav-item--icon");
472+
expect(iconWrapper).not.toBeInTheDocument();
473+
});
474+
475+
it("should render icon inside nav link in container tabs", () => {
476+
const { container } = render(TabIconContainer, {
477+
props: { icon: Calendar },
478+
});
479+
480+
const navLink = container.querySelector(".bx--tabs__nav-link");
481+
const iconWrapper = navLink?.querySelector(".bx--tabs__nav-item--icon");
482+
expect(iconWrapper).toBeInTheDocument();
483+
});
484+
485+
it("should render label and icon together in container tabs", () => {
486+
render(TabIconContainer, {
487+
props: { label: "Dashboard", icon: Calendar },
488+
});
489+
490+
const tab = screen.getByRole("tab", { name: /Dashboard/ });
491+
expect(tab).toBeInTheDocument();
492+
expect(tab.querySelector(".bx--tabs__nav-item--icon")).toBeInTheDocument();
493+
});
494+
495+
it("should apply disabled styling when tab with icon is disabled in container", () => {
496+
const { container } = render(TabIconContainer, {
497+
props: { icon: Settings, disabled: true },
498+
});
499+
500+
const disabledItem = container.querySelector(
501+
".bx--tabs__nav-item--disabled",
502+
);
503+
expect(disabledItem).toBeInTheDocument();
504+
505+
const iconWrapper = disabledItem?.querySelector(
506+
".bx--tabs__nav-item--icon",
507+
);
508+
expect(iconWrapper).toBeInTheDocument();
509+
});
510+
511+
it("should be clickable with icon when enabled in container tabs", async () => {
512+
render(TabIconContainer, { props: { icon: Calendar } });
513+
514+
const tab = screen.getByRole("tab", { name: /Test Tab/ });
515+
await user.click(tab);
516+
517+
expect(tab).toHaveAttribute("aria-selected", "true");
518+
});
519+
});
520+
445521
describe("TabsSkeleton", () => {
446522
it("should render with default props", () => {
447523
const { container } = render(TabsSkeleton);

0 commit comments

Comments
 (0)