From 38ee3a28b976dcef1d6bec53e06b93e7a84cf8f7 Mon Sep 17 00:00:00 2001 From: Airike Jaska <95303654+airikej@users.noreply.github.com> Date: Mon, 26 Jan 2026 11:00:16 +0200 Subject: [PATCH 1/3] feat(closing-button): add brand and inverted color #6 --- .../closing-button/closing-button.module.scss | 77 ++++++++++++++----- .../closing-button/closing-button.spec.tsx | 52 ++++++------- .../closing-button/closing-button.stories.tsx | 38 ++++++++- .../buttons/closing-button/closing-button.tsx | 11 ++- 4 files changed, 127 insertions(+), 51 deletions(-) diff --git a/src/tedi/components/buttons/closing-button/closing-button.module.scss b/src/tedi/components/buttons/closing-button/closing-button.module.scss index 16f010cfb..fbf28dec9 100644 --- a/src/tedi/components/buttons/closing-button/closing-button.module.scss +++ b/src/tedi/components/buttons/closing-button/closing-button.module.scss @@ -1,28 +1,12 @@ .tedi-closing-button { - --general-icon-primary: var(--button-close-text-default); - display: flex; align-items: center; justify-content: center; padding: 0; cursor: pointer; - background-color: var(--button-close-background-default); - border: 1px solid var(--button-close-background-default); + border: 0; border-radius: var(--button-radius-default); - transition: background 0.5s ease; - - @each $state in hover, active { - &:#{ $state } { - --general-icon-primary: var(--button-close-text-#{$state}); - - background-color: var(--button-close-background-#{$state}); - } - } - - &:focus-visible { - outline: 2px solid var(--button-main-primary-border-focus); - outline-offset: -2px; - } + transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease; &--medium { width: var(--button-xs-icon-size); @@ -33,4 +17,61 @@ width: var(--button-sm-icon-size); height: var(--button-sm-icon-size); } + + &--color-primary { + color: var(--button-close-text-default); + background-color: var(--button-close-background-default); + + &:hover { + color: var(--button-close-text-hover); + background-color: var(--button-close-background-hover); + } + + &:active { + color: var(--button-close-text-active); + background-color: var(--button-close-background-active); + } + + &:focus-visible { + outline: 2px solid var(--button-main-primary-border-focus); + } + } + + &--color-brand { + color: var(--button-main-neutral-text-default); + background-color: var(--button-main-neutral-icon-only-background-default); + + &:hover { + color: var(--button-main-neutral-text-hover); + background-color: var(--button-main-neutral-icon-only-background-hover); + } + + &:active { + color: var(--button-main-neutral-text-active); + background-color: var(--button-main-neutral-icon-only-background-active); + } + + &:focus-visible { + outline: 2px solid var(--button-main-primary-border-focus); + } + } + + &--color-white { + color: var(--button-neutral-inverted-text-default); + background-color: var(--button-neutral-inverted-icon-only-background-default); + + &:hover { + color: var(--button-neutral-inverted-text-hover); + background-color: var(--button-main-neutral-inverted-icon-only-background-hover); + } + + &:active { + color: var(--button-neutral-inverted-text-active); + background-color: var(--button-main-neutral-inverted-icon-only-background-hover); + } + + &:focus-visible { + outline: 2px solid var(--button-main-neutral-inverted-text-focus); + } + } } diff --git a/src/tedi/components/buttons/closing-button/closing-button.spec.tsx b/src/tedi/components/buttons/closing-button/closing-button.spec.tsx index 8bc45184d..964e5207f 100644 --- a/src/tedi/components/buttons/closing-button/closing-button.spec.tsx +++ b/src/tedi/components/buttons/closing-button/closing-button.spec.tsx @@ -10,18 +10,11 @@ jest.mock('../../../providers/label-provider', () => ({ describe('ClosingButton component', () => { it('renders the ClosingButton with default props', () => { - render( - { - console.log('Button pressed'); - }} - /> - ); + render(); const button = screen.getByRole('button', { name: /close/i }); expect(button).toBeInTheDocument(); - expect(button).toHaveClass('tedi-closing-button'); + expect(button).toHaveClass('tedi-closing-button tedi-closing-button--medium tedi-closing-button--color-primary'); const icon = button.querySelector('span[data-name="icon"]'); expect(icon).toBeInTheDocument(); @@ -29,53 +22,56 @@ describe('ClosingButton component', () => { }); it('renders with the correct large size class and icon size', () => { - render( - { - console.log('Button pressed'); - }} - /> - ); + render(); const button = screen.getByRole('button', { name: /close/i }); - expect(button).toBeInTheDocument(); - expect(button).toHaveClass('tedi-closing-button tedi-closing-button--large'); + expect(button).toHaveClass('tedi-closing-button tedi-closing-button--large tedi-closing-button--color-primary'); const icon = button.querySelector('span[data-name="icon"]'); - expect(icon).toBeInTheDocument(); expect(icon).toHaveClass('tedi-icon--size-24'); }); it('applies custom class names', () => { - render(); + render(); - const button = screen.getByRole('button', { name: /Close/i }); - expect(button).toHaveClass('tedi-closing-button tedi-closing-button--large custom-class'); + const button = screen.getByRole('button', { name: /close/i }); + expect(button).toHaveClass( + 'tedi-closing-button tedi-closing-button--medium tedi-closing-button--color-primary custom-class' + ); }); it('triggers onClick handler when clicked', () => { const onClickMock = jest.fn(); - render(); + render(); - const button = screen.getByRole('button', { name: /Close/i }); + const button = screen.getByRole('button', { name: /close/i }); fireEvent.click(button); expect(onClickMock).toHaveBeenCalledTimes(1); }); it('uses fallback label from label provider when title is not provided', () => { - render(); + render(); - const button = screen.getByRole('button', { name: /Close/i }); + const button = screen.getByRole('button', { name: /close/i }); expect(button).toHaveAttribute('title', 'Close'); expect(button).toHaveAttribute('aria-label', 'Close'); }); it('uses custom title if provided', () => { - render(); + render(); const button = screen.getByRole('button', { name: /Custom Close/i }); expect(button).toHaveAttribute('title', 'Custom Close'); expect(button).toHaveAttribute('aria-label', 'Custom Close'); }); + + it('applies the correct color classes', () => { + const colors: Array<'primary' | 'brand' | 'white'> = ['primary', 'brand', 'white']; + + colors.forEach((color) => { + const { container } = render(); + const button = container.querySelector('button[data-name="closing-button"]'); + expect(button).toHaveClass(`tedi-closing-button--color-${color}`); + }); + }); }); diff --git a/src/tedi/components/buttons/closing-button/closing-button.stories.tsx b/src/tedi/components/buttons/closing-button/closing-button.stories.tsx index 69528a74f..03497dbe3 100644 --- a/src/tedi/components/buttons/closing-button/closing-button.stories.tsx +++ b/src/tedi/components/buttons/closing-button/closing-button.stories.tsx @@ -1,5 +1,6 @@ import { Meta, StoryFn, StoryObj } from '@storybook/react'; +import { Text } from '../../base/typography/text/text'; import { Col, Row } from '../../layout/grid'; import ClosingButton, { ClosingButtonProps } from './closing-button'; @@ -41,16 +42,18 @@ const SizeTemplate: StoryFn = () => { const stateArray = ['Default', 'Hover', 'Active', 'Focus']; -const StatesTemplate: StoryFn = () => { +const StatesTemplate: StoryFn = (args) => { return (
{stateArray.map((state) => ( - {state} + + {state} + - + ))} @@ -79,3 +82,32 @@ export const States: Story = { }, }, }; + +export const ColorBrand: Story = { + render: StatesTemplate, + args: { + color: 'brand', + }, + parameters: { + pseudo: { + hover: '#Hover', + active: '#Active', + focusVisible: '#Focus', + }, + }, +}; + +export const ColorInverted: Story = { + render: StatesTemplate, + args: { + color: 'white', + }, + parameters: { + pseudo: { + hover: '#Hover', + active: '#Active', + focusVisible: '#Focus', + }, + backgrounds: { default: 'brand' }, + }, +}; diff --git a/src/tedi/components/buttons/closing-button/closing-button.tsx b/src/tedi/components/buttons/closing-button/closing-button.tsx index b718964f6..3052a0041 100644 --- a/src/tedi/components/buttons/closing-button/closing-button.tsx +++ b/src/tedi/components/buttons/closing-button/closing-button.tsx @@ -7,6 +7,7 @@ import { Icon } from '../../base/icon/icon'; import styles from './closing-button.module.scss'; type ClosingButtonSize = 'medium' | 'large'; +type ClosingButtonColor = 'primary' | 'brand' | 'white'; export interface ClosingButtonProps extends ButtonHTMLAttributes { /** @@ -27,16 +28,22 @@ export interface ClosingButtonProps extends ButtonHTMLAttributes { const { getLabel } = useLabels(); - const { title = getLabel('close'), onClick, size = 'medium', className, ...rest } = props; + const { title = getLabel('close'), onClick, size = 'medium', className, color = 'primary', ...rest } = props; const buttonClass = cn( styles['tedi-closing-button'], { [styles[`tedi-closing-button--${size}`]]: size, + [styles[`tedi-closing-button--color-${color}`]]: color, }, className ); @@ -53,7 +60,7 @@ export const ClosingButton = (props: ClosingButtonProps): JSX.Element => { title={title} aria-label={title} > - + ); }; From b499222778ed907c25c484eafbaa7acae9c045f7 Mon Sep 17 00:00:00 2001 From: Airike Jaska <95303654+airikej@users.noreply.github.com> Date: Fri, 30 Jan 2026 09:40:14 +0200 Subject: [PATCH 2/3] fix(closing-button): inherit icon color, fix primary focus color #6 --- .../closing-button/closing-button.module.scss | 11 ++++--- .../closing-button/closing-button.spec.tsx | 33 ++++++------------- .../buttons/closing-button/closing-button.tsx | 2 +- 3 files changed, 17 insertions(+), 29 deletions(-) diff --git a/src/tedi/components/buttons/closing-button/closing-button.module.scss b/src/tedi/components/buttons/closing-button/closing-button.module.scss index e0e66541b..628e9b58e 100644 --- a/src/tedi/components/buttons/closing-button/closing-button.module.scss +++ b/src/tedi/components/buttons/closing-button/closing-button.module.scss @@ -13,6 +13,11 @@ height: var(--button-sm-icon-size); } + &--small { + width: var(--button-xs-icon-size); + height: var(--button-xs-icon-size); + } + &--color-primary { color: var(--button-close-text-default); background-color: var(--button-close-background-default); @@ -28,6 +33,7 @@ } &:focus-visible { + color: var(--button-close-text-focus); outline: 2px solid var(--button-main-primary-border-focus); } } @@ -68,10 +74,5 @@ &:focus-visible { outline: 2px solid var(--button-main-neutral-inverted-text-focus); } - - &--small { - width: var(--button-xs-icon-size); - height: var(--button-xs-icon-size); - } } } diff --git a/src/tedi/components/buttons/closing-button/closing-button.spec.tsx b/src/tedi/components/buttons/closing-button/closing-button.spec.tsx index b1c809559..9e27d065a 100644 --- a/src/tedi/components/buttons/closing-button/closing-button.spec.tsx +++ b/src/tedi/components/buttons/closing-button/closing-button.spec.tsx @@ -14,18 +14,18 @@ describe('ClosingButton component', () => { const button = screen.getByRole('button', { name: /close/i }); expect(button).toBeInTheDocument(); - expect(button).toHaveClass('tedi-closing-button tedi-closing-button--medium tedi-closing-button--color-primary'); + expect(button).toHaveClass('tedi-closing-button tedi-closing-button--default tedi-closing-button--color-primary'); const icon = button.querySelector('span[data-name="icon"]'); expect(icon).toBeInTheDocument(); - expect(icon).toHaveClass('tedi-icon--size-18'); + expect(icon).toHaveClass('tedi-icon--size-24'); }); - it('renders with the correct large size class and icon size', () => { - render(); + it('renders with the correct small size class and icon size', () => { + render(); const button = screen.getByRole('button', { name: /close/i }); - expect(button).toHaveClass('tedi-closing-button tedi-closing-button--large tedi-closing-button--color-primary'); + expect(button).toHaveClass('tedi-closing-button tedi-closing-button--small tedi-closing-button--color-primary'); render( { @@ -34,24 +34,11 @@ describe('ClosingButton component', () => { /> ); - const button = screen.getByRole('button', { name: /close/i }); expect(button).toBeInTheDocument(); expect(button).toHaveClass('tedi-closing-button'); - expect(button).toHaveClass('tedi-closing-button--default'); - - const icon = button.querySelector('span[data-name="icon"]'); - expect(icon).toHaveClass('tedi-icon--size-24'); - }); - - it('renders with small size when size="small"', () => { - render(); - - const button = screen.getByRole('button', { name: /close/i }); expect(button).toHaveClass('tedi-closing-button--small'); const icon = button.querySelector('span[data-name="icon"]'); - expect(icon).toBeInTheDocument(); - // Small button still uses default icon size expect(icon).toHaveClass('tedi-icon--size-24'); }); @@ -71,12 +58,12 @@ describe('ClosingButton component', () => { const button = screen.getByRole('button', { name: /close/i }); expect(button).toHaveClass( - 'tedi-closing-button tedi-closing-button--medium tedi-closing-button--color-primary custom-class' + 'tedi-closing-button tedi-closing-button--default tedi-closing-button--color-primary custom-class' ); - const button = screen.getByRole('button', { name: /Close/i }); - expect(button).toHaveClass('tedi-closing-button'); - expect(button).toHaveClass('tedi-closing-button--default'); - expect(button).toHaveClass('custom-class'); + const customButton = screen.getByRole('button', { name: /Close/i }); + expect(customButton).toHaveClass('tedi-closing-button'); + expect(customButton).toHaveClass('tedi-closing-button--default'); + expect(customButton).toHaveClass('custom-class'); }); it('triggers onClick handler when clicked', () => { diff --git a/src/tedi/components/buttons/closing-button/closing-button.tsx b/src/tedi/components/buttons/closing-button/closing-button.tsx index 5a1160d32..dc4aa4f3d 100644 --- a/src/tedi/components/buttons/closing-button/closing-button.tsx +++ b/src/tedi/components/buttons/closing-button/closing-button.tsx @@ -77,7 +77,7 @@ export const ClosingButton = (props: ClosingButtonProps): JSX.Element => { title={title} aria-label={title} > - + ); }; From 44f4c310bea9e6d9df8ef1721f799a3e514666e7 Mon Sep 17 00:00:00 2001 From: Airike Jaska <95303654+airikej@users.noreply.github.com> Date: Thu, 19 Feb 2026 11:06:01 +0200 Subject: [PATCH 3/3] fix(closing-button): improve prop description #6 --- src/tedi/components/buttons/closing-button/closing-button.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tedi/components/buttons/closing-button/closing-button.tsx b/src/tedi/components/buttons/closing-button/closing-button.tsx index dc4aa4f3d..0eb7c77a5 100644 --- a/src/tedi/components/buttons/closing-button/closing-button.tsx +++ b/src/tedi/components/buttons/closing-button/closing-button.tsx @@ -17,7 +17,7 @@ export interface ClosingButtonProps extends ButtonHTMLAttributes