From c29bdcb89f37b403e0422cb72d800042a3ec9de2 Mon Sep 17 00:00:00 2001 From: Marius Tobiassen Bungum Date: Wed, 21 Jan 2026 12:49:02 +0100 Subject: [PATCH 1/3] chore: Update gitignore --- .gitignore | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 793d0ff58..d728b36e1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,5 @@ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. -# Webstorm specific -.idea/workspace.xml - package-lock.json # dependencies @@ -17,6 +14,7 @@ package-lock.json # Webstorm user specific settings .idea/workspace.xml +.idea/vcs.xml # production /build From 13bebc4f52fed4164a9081c9118e328f586b7504 Mon Sep 17 00:00:00 2001 From: Marius Tobiassen Bungum Date: Wed, 21 Jan 2026 12:51:04 +0100 Subject: [PATCH 2/3] style: New text hover color on inactive tab --- src/molecules/Tabs/Tab.styles.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/molecules/Tabs/Tab.styles.ts b/src/molecules/Tabs/Tab.styles.ts index 1b017b6e8..f49c39e6e 100644 --- a/src/molecules/Tabs/Tab.styles.ts +++ b/src/molecules/Tabs/Tab.styles.ts @@ -44,6 +44,9 @@ export const Button = styled.button` &:hover:not(:disabled) { background: ${colors.interactive.primary__hover_alt.rgba}; + > label { + color: ${colors.text.static_icons__secondary.rgba}; + } &[aria-selected='true'] { > svg { From c06bf2a105aa35e8add6f0635d3509ff7330bf86 Mon Sep 17 00:00:00 2001 From: Marius Tobiassen Bungum Date: Wed, 21 Jan 2026 12:51:46 +0100 Subject: [PATCH 3/3] feat: Added 'trailingIcon' and 'variant' to Tabs options --- src/molecules/Tabs/Tab.tsx | 29 ++++++++++- src/molecules/Tabs/Tabs.stories.tsx | 81 ++++++++++++++++++++++++++++- src/molecules/Tabs/Tabs.types.ts | 5 ++ 3 files changed, 113 insertions(+), 2 deletions(-) diff --git a/src/molecules/Tabs/Tab.tsx b/src/molecules/Tabs/Tab.tsx index b22437982..c9ec82e42 100644 --- a/src/molecules/Tabs/Tab.tsx +++ b/src/molecules/Tabs/Tab.tsx @@ -2,6 +2,16 @@ import { Icon, Typography } from '@equinor/eds-core-react'; import { ActiveLine, Button, Count, Line } from './Tab.styles'; import { Tab as TabType, Tabs } from './Tabs.types'; +import { colors } from 'src/atoms/style/colors'; +import { getVariantIcon } from 'src/atoms/utils'; + +const VARIANT_ICON_COLORS: Record< + Required, 'variant'>>['variant'], + string +> = { + warning: colors.interactive.warning__text.rgba, + error: colors.interactive.danger__text.rgba, +} as const; type TabProps = { onChange: Tabs['onChange']; @@ -23,8 +33,12 @@ export function Tab({ animated, disabled, leadingIcon, + trailingIcon, + variant, count, }: TabProps) { + const usingLeadingIcon = variant ? getVariantIcon(variant) : leadingIcon; + const handleOnClick = () => { onChange(value); }; @@ -43,7 +57,19 @@ export function Tab({ $centered={centered} disabled={disabled} > - {leadingIcon ? : null} + {usingLeadingIcon ? ( + + ) : null} {label} @@ -54,6 +80,7 @@ export function Tab({ ) : null} + {trailingIcon ? : null} {animated ? ( <> diff --git a/src/molecules/Tabs/Tabs.stories.tsx b/src/molecules/Tabs/Tabs.stories.tsx index 74909ed9e..c98042db2 100644 --- a/src/molecules/Tabs/Tabs.stories.tsx +++ b/src/molecules/Tabs/Tabs.stories.tsx @@ -5,9 +5,10 @@ import { Meta, StoryObj } from '@storybook/react-vite'; import { Tabs } from './Tabs'; import { Tab, Tabs as TabsType } from './Tabs.types'; +import { getVariantIcon } from 'src/atoms/utils'; import { PartialStoryFn } from 'storybook/internal/types'; -import { expect, fn, userEvent } from 'storybook/test'; +import { expect, fn, userEvent, within } from 'storybook/test'; const OPTIONS: [Tab, Tab, Tab] = [ { @@ -114,6 +115,84 @@ export const WithLeadingIcon: Story = { }, ], }, + play: async ({ canvas, args }) => { + for (const item of args.options) { + const tabElement = canvas.getByRole('tab', { name: item.label }); + const icon = within(tabElement).getByTestId('eds-icon-path'); + await expect(icon).toBeInTheDocument(); + await expect(icon).toHaveAttribute( + 'd', + item.leadingIcon?.svgPathData as string + ); + } + }, +}; + +export const WithTrailingIcon: Story = { + args: { + options: [ + { + value: 1, + trailingIcon: car, + label: 'トヨタ', + }, + { + value: 2, + trailingIcon: gamepad, + label: '任天堂', + }, + { + value: 3, + trailingIcon: motorcycle, + label: 'ヤマハ', + }, + ], + }, + play: async ({ canvas, args }) => { + for (const item of args.options) { + const tabElement = canvas.getByRole('tab', { name: item.label }); + const icon = within(tabElement).getByTestId('eds-icon-path'); + await expect(icon).toBeInTheDocument(); + await expect(icon).toHaveAttribute( + 'd', + item.trailingIcon?.svgPathData as string + ); + } + }, +}; + +export const Variants: Story = { + args: { + options: [ + { + value: 1, + variant: 'error', + label: 'トヨタ', + }, + { + value: 2, + variant: 'warning', + label: '任天堂', + }, + { + value: 3, + leadingIcon: motorcycle, + label: 'ヤマハ', + }, + ], + }, + play: async ({ canvas, args }) => { + const errorTab = canvas.getByRole('tab', { name: args.options[0].label }); + await expect(within(errorTab).getByTestId('eds-icon-path')).toHaveAttribute( + 'd', + getVariantIcon('error').svgPathData as string + ); + + const warningTab = canvas.getByRole('tab', { name: args.options[1].label }); + await expect( + within(warningTab).getByTestId('eds-icon-path') + ).toHaveAttribute('d', getVariantIcon('warning').svgPathData as string); + }, }; export const WithCount: Story = { diff --git a/src/molecules/Tabs/Tabs.types.ts b/src/molecules/Tabs/Tabs.types.ts index 5945af25c..50434457a 100644 --- a/src/molecules/Tabs/Tabs.types.ts +++ b/src/molecules/Tabs/Tabs.types.ts @@ -1,12 +1,17 @@ import { IconData } from '@equinor/eds-icons'; +import { Variants } from 'src/atoms/types/variants'; + export interface Tab { value: T; label: string; count?: number; leadingIcon?: IconData; + trailingIcon?: IconData; + variant?: Extract; disabled?: boolean; } + export interface Tabs { selected: T; onChange: (value: T) => void;