Skip to content

Commit f93793a

Browse files
authored
feat: Tabs variants and trailingIcon (#1210)
* chore: Update gitignore * style: New text hover color on inactive tab * feat: Added 'trailingIcon' and 'variant' to Tabs options
1 parent ac00f95 commit f93793a

5 files changed

Lines changed: 117 additions & 5 deletions

File tree

.gitignore

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
22

3-
# Webstorm specific
4-
.idea/workspace.xml
5-
63
package-lock.json
74

85
# dependencies
@@ -17,6 +14,7 @@ package-lock.json
1714

1815
# Webstorm user specific settings
1916
.idea/workspace.xml
17+
.idea/vcs.xml
2018

2119
# production
2220
/build

src/molecules/Tabs/Tab.styles.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ export const Button = styled.button<ButtonProps>`
4444
4545
&:hover:not(:disabled) {
4646
background: ${colors.interactive.primary__hover_alt.rgba};
47+
> label {
48+
color: ${colors.text.static_icons__secondary.rgba};
49+
}
4750
4851
&[aria-selected='true'] {
4952
> svg {

src/molecules/Tabs/Tab.tsx

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@ import { Icon, Typography } from '@equinor/eds-core-react';
22

33
import { ActiveLine, Button, Count, Line } from './Tab.styles';
44
import { Tab as TabType, Tabs } from './Tabs.types';
5+
import { colors } from 'src/atoms/style/colors';
6+
import { getVariantIcon } from 'src/atoms/utils';
7+
8+
const VARIANT_ICON_COLORS: Record<
9+
Required<Pick<TabType<unknown>, 'variant'>>['variant'],
10+
string
11+
> = {
12+
warning: colors.interactive.warning__text.rgba,
13+
error: colors.interactive.danger__text.rgba,
14+
} as const;
515

616
type TabProps<T> = {
717
onChange: Tabs<T>['onChange'];
@@ -23,8 +33,12 @@ export function Tab<T>({
2333
animated,
2434
disabled,
2535
leadingIcon,
36+
trailingIcon,
37+
variant,
2638
count,
2739
}: TabProps<T>) {
40+
const usingLeadingIcon = variant ? getVariantIcon(variant) : leadingIcon;
41+
2842
const handleOnClick = () => {
2943
onChange(value);
3044
};
@@ -43,7 +57,19 @@ export function Tab<T>({
4357
$centered={centered}
4458
disabled={disabled}
4559
>
46-
{leadingIcon ? <Icon data={leadingIcon} size={24} /> : null}
60+
{usingLeadingIcon ? (
61+
<Icon
62+
data={usingLeadingIcon}
63+
size={24}
64+
style={
65+
variant
66+
? {
67+
fill: VARIANT_ICON_COLORS[variant],
68+
}
69+
: undefined
70+
}
71+
/>
72+
) : null}
4773
<Typography as="label" variant="menu_tabs" group="navigation">
4874
{label}
4975
</Typography>
@@ -54,6 +80,7 @@ export function Tab<T>({
5480
</Typography>
5581
</Count>
5682
) : null}
83+
{trailingIcon ? <Icon data={trailingIcon} size={24} /> : null}
5784
{animated ? (
5885
<>
5986
<Line className="static-line" />

src/molecules/Tabs/Tabs.stories.tsx

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ import { Meta, StoryObj } from '@storybook/react-vite';
55

66
import { Tabs } from './Tabs';
77
import { Tab, Tabs as TabsType } from './Tabs.types';
8+
import { getVariantIcon } from 'src/atoms/utils';
89

910
import { PartialStoryFn } from 'storybook/internal/types';
10-
import { expect, fn, userEvent } from 'storybook/test';
11+
import { expect, fn, userEvent, within } from 'storybook/test';
1112

1213
const OPTIONS: [Tab<number>, Tab<number>, Tab<number>] = [
1314
{
@@ -114,6 +115,84 @@ export const WithLeadingIcon: Story = {
114115
},
115116
],
116117
},
118+
play: async ({ canvas, args }) => {
119+
for (const item of args.options) {
120+
const tabElement = canvas.getByRole('tab', { name: item.label });
121+
const icon = within(tabElement).getByTestId('eds-icon-path');
122+
await expect(icon).toBeInTheDocument();
123+
await expect(icon).toHaveAttribute(
124+
'd',
125+
item.leadingIcon?.svgPathData as string
126+
);
127+
}
128+
},
129+
};
130+
131+
export const WithTrailingIcon: Story = {
132+
args: {
133+
options: [
134+
{
135+
value: 1,
136+
trailingIcon: car,
137+
label: 'トヨタ',
138+
},
139+
{
140+
value: 2,
141+
trailingIcon: gamepad,
142+
label: '任天堂',
143+
},
144+
{
145+
value: 3,
146+
trailingIcon: motorcycle,
147+
label: 'ヤマハ',
148+
},
149+
],
150+
},
151+
play: async ({ canvas, args }) => {
152+
for (const item of args.options) {
153+
const tabElement = canvas.getByRole('tab', { name: item.label });
154+
const icon = within(tabElement).getByTestId('eds-icon-path');
155+
await expect(icon).toBeInTheDocument();
156+
await expect(icon).toHaveAttribute(
157+
'd',
158+
item.trailingIcon?.svgPathData as string
159+
);
160+
}
161+
},
162+
};
163+
164+
export const Variants: Story = {
165+
args: {
166+
options: [
167+
{
168+
value: 1,
169+
variant: 'error',
170+
label: 'トヨタ',
171+
},
172+
{
173+
value: 2,
174+
variant: 'warning',
175+
label: '任天堂',
176+
},
177+
{
178+
value: 3,
179+
leadingIcon: motorcycle,
180+
label: 'ヤマハ',
181+
},
182+
],
183+
},
184+
play: async ({ canvas, args }) => {
185+
const errorTab = canvas.getByRole('tab', { name: args.options[0].label });
186+
await expect(within(errorTab).getByTestId('eds-icon-path')).toHaveAttribute(
187+
'd',
188+
getVariantIcon('error').svgPathData as string
189+
);
190+
191+
const warningTab = canvas.getByRole('tab', { name: args.options[1].label });
192+
await expect(
193+
within(warningTab).getByTestId('eds-icon-path')
194+
).toHaveAttribute('d', getVariantIcon('warning').svgPathData as string);
195+
},
117196
};
118197

119198
export const WithCount: Story = {

src/molecules/Tabs/Tabs.types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
import { IconData } from '@equinor/eds-icons';
22

3+
import { Variants } from 'src/atoms/types/variants';
4+
35
export interface Tab<T> {
46
value: T;
57
label: string;
68
count?: number;
79
leadingIcon?: IconData;
10+
trailingIcon?: IconData;
11+
variant?: Extract<Variants, 'warning' | 'error'>;
812
disabled?: boolean;
913
}
14+
1015
export interface Tabs<T> {
1116
selected: T;
1217
onChange: (value: T) => void;

0 commit comments

Comments
 (0)