From f6fdfd71cc8abaed2f3d42da3bb8b0bffc790ca4 Mon Sep 17 00:00:00 2001 From: Sjur Sutterud Sagen Date: Wed, 6 May 2026 10:47:50 +0200 Subject: [PATCH 01/15] Update two global colors --- packages/pxweb2-ui/style-dictionary/src/default_theme.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/pxweb2-ui/style-dictionary/src/default_theme.json b/packages/pxweb2-ui/style-dictionary/src/default_theme.json index 3e26c350e..d17e0c5b5 100644 --- a/packages/pxweb2-ui/style-dictionary/src/default_theme.json +++ b/packages/pxweb2-ui/style-dictionary/src/default_theme.json @@ -33,7 +33,6 @@ "transparent": { "value": "#FFFFFF00" } - }, "brand-alpha": { "800": { @@ -60,7 +59,7 @@ "value": "#F5533D" }, "600": { - "value": "#E23822" + "value": "#DD2913" }, "700": { "value": "#BF2B18" @@ -92,7 +91,7 @@ "value": "#EB9C07" }, "600": { - "value": "#CB7603" + "value": "#D6850F" }, "700": { "value": "#A25206" From a46cbc770539efd76c491a83ea691ade809bce9e Mon Sep 17 00:00:00 2001 From: Sjur Sutterud Sagen Date: Wed, 6 May 2026 12:54:55 +0200 Subject: [PATCH 02/15] Add 4 new semantic colors --- .../style-dictionary/src/default_theme.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/pxweb2-ui/style-dictionary/src/default_theme.json b/packages/pxweb2-ui/style-dictionary/src/default_theme.json index d17e0c5b5..b5eed5f09 100644 --- a/packages/pxweb2-ui/style-dictionary/src/default_theme.json +++ b/packages/pxweb2-ui/style-dictionary/src/default_theme.json @@ -311,24 +311,36 @@ "neutral-moderate": { "value": "{color.neutral.200}" }, + "info": { + "value": "{color.info.600}" + }, "info-subtle": { "value": "{color.info.100}" }, "info-moderate": { "value": "{color.info.200}" }, + "success": { + "value": "{color.success.600}" + }, "success-subtle": { "value": "{color.success.100}" }, "success-moderate": { "value": "{color.success.200}" }, + "warning": { + "value": "{color.warning.600}" + }, "warning-subtle": { "value": "{color.warning.100}" }, "warning-moderate": { "value": "{color.warning.200}" }, + "error": { + "value": "{color.danger.600}" + }, "error-subtle": { "value": "{color.danger.100}" }, From 9fe84bfc65204f46e2119f213ee3b43cc0219664 Mon Sep 17 00:00:00 2001 From: Sjur Sutterud Sagen Date: Wed, 6 May 2026 15:14:45 +0200 Subject: [PATCH 03/15] Fix color values for danger and warning states; add surface color variables for info, success, warning, and error --- packages/pxweb2/public/theme/variables.css | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/pxweb2/public/theme/variables.css b/packages/pxweb2/public/theme/variables.css index 235d70d44..472accb58 100644 --- a/packages/pxweb2/public/theme/variables.css +++ b/packages/pxweb2/public/theme/variables.css @@ -20,7 +20,7 @@ --px-color-danger-300: #FFBBB3; --px-color-danger-400: #FD7E6D; --px-color-danger-500: #F5533D; - --px-color-danger-600: #E23822; + --px-color-danger-600: #DD2913; --px-color-danger-700: #BF2B18; --px-color-danger-800: #8A2215; --px-color-danger-900: #5E1D13; @@ -30,7 +30,7 @@ --px-color-warning-300: #FED85D; --px-color-warning-400: #FCBF27; --px-color-warning-500: #EB9C07; - --px-color-warning-600: #CB7603; + --px-color-warning-600: #D6850F; --px-color-warning-700: #A25206; --px-color-warning-800: #783B0D; --px-color-warning-900: #47210B; @@ -99,12 +99,16 @@ --px-color-surface-action-subtle-active: var(--px-color-brand-200); --px-color-surface-neutral-subtle: var(--px-color-neutral-100); --px-color-surface-neutral-moderate: var(--px-color-neutral-200); + --px-color-surface-info: var(--px-color-info-600); --px-color-surface-info-subtle: var(--px-color-info-100); --px-color-surface-info-moderate: var(--px-color-info-200); + --px-color-surface-success: var(--px-color-success-600); --px-color-surface-success-subtle: var(--px-color-success-100); --px-color-surface-success-moderate: var(--px-color-success-200); + --px-color-surface-warning: var(--px-color-warning-600); --px-color-surface-warning-subtle: var(--px-color-warning-100); --px-color-surface-warning-moderate: var(--px-color-warning-200); + --px-color-surface-error: var(--px-color-danger-600); --px-color-surface-error-subtle: var(--px-color-danger-100); --px-color-surface-error-moderate: var(--px-color-danger-200); --px-color-border-default: var(--px-color-brand-900); From a29a199671747651ee380e2eb0b97c7d8ba0e519 Mon Sep 17 00:00:00 2001 From: Sjur Sutterud Sagen Date: Wed, 6 May 2026 16:05:27 +0200 Subject: [PATCH 04/15] Add badge component with stories and unittests --- .../lib/components/Badge/Badge.module.scss | 84 +++++++++++ .../src/lib/components/Badge/Badge.spec.tsx | 82 +++++++++++ .../lib/components/Badge/Badge.stories.tsx | 136 ++++++++++++++++++ .../src/lib/components/Badge/Badge.tsx | 35 +++++ 4 files changed, 337 insertions(+) create mode 100644 packages/pxweb2-ui/src/lib/components/Badge/Badge.module.scss create mode 100644 packages/pxweb2-ui/src/lib/components/Badge/Badge.spec.tsx create mode 100644 packages/pxweb2-ui/src/lib/components/Badge/Badge.stories.tsx create mode 100644 packages/pxweb2-ui/src/lib/components/Badge/Badge.tsx diff --git a/packages/pxweb2-ui/src/lib/components/Badge/Badge.module.scss b/packages/pxweb2-ui/src/lib/components/Badge/Badge.module.scss new file mode 100644 index 000000000..5e9a0e5b7 --- /dev/null +++ b/packages/pxweb2-ui/src/lib/components/Badge/Badge.module.scss @@ -0,0 +1,84 @@ +@use '../../text-styles.scss'; + +.badge { + display: flex; + justify-content: center; + align-items: center; + color: var(--px-color-text-default); + width: fit-content; +} + +/* Colors and variants */ +.color-neutral { + &.variant-default { + background-color: var(--px-color-surface-moderate); + } + &.variant-subtle { + background-color: var(--px-color-surface-subtle); + } +} +.color-info { + &.variant-default { + color: var(--px-color-text-on-inverted); + background-color: var(--px-color-surface-info); + } + &.variant-subtle { + background-color: var(--px-color-surface-info-moderate); + } +} +.color-success { + &.variant-default { + color: var(--px-color-text-on-inverted); + background-color: var(--px-color-surface-success); + } + &.variant-subtle { + background-color: var(--px-color-surface-success-moderate); + } +} +.color-warning { + &.variant-default { + background-color: var(--px-color-surface-warning); + } + &.variant-subtle { + background-color: var(--px-color-surface-warning-moderate); + } +} +.color-error { + &.variant-default { + color: var(--px-color-text-on-inverted); + background-color: var(--px-color-surface-error); + } + &.variant-subtle { + background-color: var(--px-color-surface-error-moderate); + } +} + +/* Sizes with or without label */ +.size-medium { + border-radius: var(--px-border-radius-small); + height: 24px; + min-width: 24px; + padding: 1px 8px 0 8px; + + &.no-label { + border-radius: var(--px-border-radius-full); + width: 12px; + min-width: 0px; + height: 12px; + padding: 0; + } +} +.size-large { + border-radius: var(--px-border-radius-small); + height: 28px; + min-width: 28px; + padding: 1px 10px 0 10px; + + &.no-label { + border-radius: var(--px-border-radius-full); + width: 14px; + min-width: 0px; + height: 14px; + padding: 0; + } +} diff --git a/packages/pxweb2-ui/src/lib/components/Badge/Badge.spec.tsx b/packages/pxweb2-ui/src/lib/components/Badge/Badge.spec.tsx new file mode 100644 index 000000000..99b8a04dd --- /dev/null +++ b/packages/pxweb2-ui/src/lib/components/Badge/Badge.spec.tsx @@ -0,0 +1,82 @@ +import { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom/vitest'; + +import { Badge } from './Badge'; +import classes from './Badge.module.scss'; + +describe('Badge', () => { + it('renders default classes when no props are provided', () => { + const { container } = render(); + const badge = container.firstElementChild as HTMLElement; + + expect(badge).toHaveClass(classes.badge); + expect(badge).toHaveClass(classes['variant-default']); + expect(badge).toHaveClass(classes['color-neutral']); + expect(badge).toHaveClass(classes['size-medium']); + expect(badge).toHaveClass(classes['no-label']); + }); + + it('renders a label when label prop is provided', () => { + render(); + + expect(screen.getByText('9')).toBeInTheDocument(); + expect(screen.getByText('9').parentElement).not.toHaveClass(classes['no-label']); + }); + + it('renders in no-label mode when label is an empty string', () => { + const { container } = render(); + const badge = container.firstElementChild as HTMLElement; + + expect(container.querySelector('span')).toBeNull(); + expect(badge).toHaveClass(classes['no-label']); + }); + + it('renders in no-label mode when label is whitespace only', () => { + const { container } = render(); + const badge = container.firstElementChild as HTMLElement; + + expect(badge).toHaveClass(classes['no-label']); + }); + + it('applies classes for selected variant, color, and size', () => { + const { container } = render( + , + ); + const badge = container.firstElementChild as HTMLElement; + + expect(badge).toHaveClass(classes['variant-subtle']); + expect(badge).toHaveClass(classes['color-error']); + expect(badge).toHaveClass(classes['size-large']); + expect(badge).not.toHaveClass(classes['no-label']); + }); + + it.each(['neutral', 'info', 'success', 'warning', 'error'] as const)( + 'applies color class for %s', + (color) => { + const { container } = render(); + const badge = container.firstElementChild as HTMLElement; + + expect(badge).toHaveClass(classes[`color-${color}`]); + }, + ); + + it.each(['default', 'subtle'] as const)( + 'applies variant class for %s', + (variant) => { + const { container } = render(); + const badge = container.firstElementChild as HTMLElement; + + expect(badge).toHaveClass(classes[`variant-${variant}`]); + }, + ); + + it.each(['medium', 'large'] as const)( + 'applies size class for %s', + (size) => { + const { container } = render(); + const badge = container.firstElementChild as HTMLElement; + + expect(badge).toHaveClass(classes[`size-${size}`]); + }, + ); +}); diff --git a/packages/pxweb2-ui/src/lib/components/Badge/Badge.stories.tsx b/packages/pxweb2-ui/src/lib/components/Badge/Badge.stories.tsx new file mode 100644 index 000000000..c4bc7ff77 --- /dev/null +++ b/packages/pxweb2-ui/src/lib/components/Badge/Badge.stories.tsx @@ -0,0 +1,136 @@ +import type { ComponentProps } from 'react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { Badge } from './Badge'; + +type BadgeProps = ComponentProps; +const colors = ['neutral', 'info', 'success', 'warning', 'error'] as const; +const sizes = ['medium', 'large'] as const; + +const meta = { + component: Badge, + title: 'Components/Badge', + tags: ['autodocs'], + args: { + variant: 'default', + color: 'neutral', + size: 'medium', + label: '9', + }, + argTypes: { + variant: { control: 'inline-radio', options: ['default', 'subtle'] }, + color: { + control: 'inline-radio', + options: ['neutral', 'info', 'success', 'warning', 'error'], + }, + size: { control: 'inline-radio', options: ['medium', 'large'] }, + label: { control: 'text' }, + }, +} satisfies Meta; + +type Story = StoryObj; +const wrapperStyle = { + display: 'flex', + flexDirection: 'column', + gap: '16px', +} as const; + +const rowStyle = { + display: 'flex', + alignItems: 'center', + gap: '12px', + flexWrap: 'wrap', +} as const; + +const labelStyle = { + minWidth: '120px', + fontWeight: 600, +} as const; + +const renderBadgeRow = ( + args: BadgeProps, + overrides: Array<{ labelText: string; badge: BadgeProps }>, +) => ( +
+ {overrides.map(({ labelText, badge }) => ( +
+ {labelText} + +
+ ))} +
+); + +export const Playground: Story = {}; + +export const SizeAndLabelStates: Story = { + render: (args) => + renderBadgeRow(args, [ + { labelText: 'Medium with label', badge: { size: 'medium', label: '9' } }, + { labelText: 'Large with label', badge: { size: 'large', label: '99' } }, + { labelText: 'Medium without label', badge: { size: 'medium', label: '' } }, + { labelText: 'Large without label', badge: { size: 'large', label: '' } }, + ]), +}; + +export const DefaultColors: Story = { + args: { variant: 'default', label: '9', size: 'medium' }, + render: (args) => ( +
+
+ {colors.map((color) => ( + + ))} +
+
+ {colors.map((color) => ( + + ))} +
+
+ ), +}; + +export const SubtleColors: Story = { + args: { variant: 'subtle', label: '9', size: 'medium' }, + render: (args) => ( +
+
+ {colors.map((color) => ( + + ))} +
+
+ {colors.map((color) => ( + + ))} +
+
+ ), +}; + +export const FullMatrix: Story = { + args: { label: '9' }, + render: (args) => ( +
+ {(['default', 'subtle'] as const).map((variant) => + sizes.map((size) => ( +
+ {`${variant} / ${size}`} + {colors.map((color) => ( + + ))} +
+ )), + )} +
+ ), +}; + +export default meta; diff --git a/packages/pxweb2-ui/src/lib/components/Badge/Badge.tsx b/packages/pxweb2-ui/src/lib/components/Badge/Badge.tsx new file mode 100644 index 000000000..5158388f3 --- /dev/null +++ b/packages/pxweb2-ui/src/lib/components/Badge/Badge.tsx @@ -0,0 +1,35 @@ +import clsx from 'clsx'; + +import classes from './Badge.module.scss'; + +interface Badge { + readonly variant?: 'default' | 'subtle'; + readonly color?: 'neutral' | 'info' | 'success' | 'warning' | 'error'; + readonly size?: 'medium' | 'large'; + readonly label?: string; +} + +export function Badge({ + variant = 'default', + color = 'neutral', + size = 'medium', + label, +}: Badge) { + const withoutLabel = !label || label.trim() === ''; + + return ( +
+ {label && {label}} +
+ ); +} + +export default Badge; From 5252f5faa64659f445f04508afe4ad289037e3c3 Mon Sep 17 00:00:00 2001 From: Sjur Sutterud Sagen Date: Wed, 6 May 2026 16:06:14 +0200 Subject: [PATCH 05/15] Fix formatting --- .../src/lib/components/Badge/Badge.spec.tsx | 17 ++++++++--------- .../lib/components/Badge/Badge.stories.tsx | 19 ++++++++++++++++--- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/packages/pxweb2-ui/src/lib/components/Badge/Badge.spec.tsx b/packages/pxweb2-ui/src/lib/components/Badge/Badge.spec.tsx index 99b8a04dd..9cae54dd9 100644 --- a/packages/pxweb2-ui/src/lib/components/Badge/Badge.spec.tsx +++ b/packages/pxweb2-ui/src/lib/components/Badge/Badge.spec.tsx @@ -20,7 +20,9 @@ describe('Badge', () => { render(); expect(screen.getByText('9')).toBeInTheDocument(); - expect(screen.getByText('9').parentElement).not.toHaveClass(classes['no-label']); + expect(screen.getByText('9').parentElement).not.toHaveClass( + classes['no-label'], + ); }); it('renders in no-label mode when label is an empty string', () => { @@ -70,13 +72,10 @@ describe('Badge', () => { }, ); - it.each(['medium', 'large'] as const)( - 'applies size class for %s', - (size) => { - const { container } = render(); - const badge = container.firstElementChild as HTMLElement; + it.each(['medium', 'large'] as const)('applies size class for %s', (size) => { + const { container } = render(); + const badge = container.firstElementChild as HTMLElement; - expect(badge).toHaveClass(classes[`size-${size}`]); - }, - ); + expect(badge).toHaveClass(classes[`size-${size}`]); + }); }); diff --git a/packages/pxweb2-ui/src/lib/components/Badge/Badge.stories.tsx b/packages/pxweb2-ui/src/lib/components/Badge/Badge.stories.tsx index c4bc7ff77..d44ffa70b 100644 --- a/packages/pxweb2-ui/src/lib/components/Badge/Badge.stories.tsx +++ b/packages/pxweb2-ui/src/lib/components/Badge/Badge.stories.tsx @@ -68,7 +68,10 @@ export const SizeAndLabelStates: Story = { renderBadgeRow(args, [ { labelText: 'Medium with label', badge: { size: 'medium', label: '9' } }, { labelText: 'Large with label', badge: { size: 'large', label: '99' } }, - { labelText: 'Medium without label', badge: { size: 'medium', label: '' } }, + { + labelText: 'Medium without label', + badge: { size: 'medium', label: '' }, + }, { labelText: 'Large without label', badge: { size: 'large', label: '' } }, ]), }; @@ -84,7 +87,12 @@ export const DefaultColors: Story = {
{colors.map((color) => ( - + ))}
@@ -102,7 +110,12 @@ export const SubtleColors: Story = {
{colors.map((color) => ( - + ))}
From 46ba95609af6b0687b1178a838349e5cbf3a4288 Mon Sep 17 00:00:00 2001 From: Sjur Sutterud Sagen Date: Thu, 7 May 2026 08:05:59 +0200 Subject: [PATCH 06/15] Refactor stories with cleanup --- .../lib/components/Badge/Badge.module.scss | 5 ++ .../lib/components/Badge/Badge.stories.tsx | 51 ++++++++++++------- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/packages/pxweb2-ui/src/lib/components/Badge/Badge.module.scss b/packages/pxweb2-ui/src/lib/components/Badge/Badge.module.scss index 5e9a0e5b7..96abe0396 100644 --- a/packages/pxweb2-ui/src/lib/components/Badge/Badge.module.scss +++ b/packages/pxweb2-ui/src/lib/components/Badge/Badge.module.scss @@ -17,6 +17,7 @@ background-color: var(--px-color-surface-subtle); } } + .color-info { &.variant-default { color: var(--px-color-text-on-inverted); @@ -26,6 +27,7 @@ background-color: var(--px-color-surface-info-moderate); } } + .color-success { &.variant-default { color: var(--px-color-text-on-inverted); @@ -35,6 +37,7 @@ background-color: var(--px-color-surface-success-moderate); } } + .color-warning { &.variant-default { background-color: var(--px-color-surface-warning); @@ -43,6 +46,7 @@ background-color: var(--px-color-surface-warning-moderate); } } + .color-error { &.variant-default { color: var(--px-color-text-on-inverted); @@ -68,6 +72,7 @@ padding: 0; } } + .size-large { border-radius: var(--px-border-radius-small); height: 28px; diff --git a/packages/pxweb2-ui/src/lib/components/Badge/Badge.stories.tsx b/packages/pxweb2-ui/src/lib/components/Badge/Badge.stories.tsx index d44ffa70b..6bca2305d 100644 --- a/packages/pxweb2-ui/src/lib/components/Badge/Badge.stories.tsx +++ b/packages/pxweb2-ui/src/lib/components/Badge/Badge.stories.tsx @@ -3,10 +3,8 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; import { Badge } from './Badge'; -type BadgeProps = ComponentProps; const colors = ['neutral', 'info', 'success', 'warning', 'error'] as const; const sizes = ['medium', 'large'] as const; - const meta = { component: Badge, title: 'Components/Badge', @@ -27,39 +25,40 @@ const meta = { label: { control: 'text' }, }, } satisfies Meta; - -type Story = StoryObj; const wrapperStyle = { display: 'flex', flexDirection: 'column', gap: '16px', } as const; - const rowStyle = { display: 'flex', alignItems: 'center', gap: '12px', flexWrap: 'wrap', } as const; - const labelStyle = { minWidth: '120px', fontWeight: 600, } as const; -const renderBadgeRow = ( +type Story = StoryObj; +type BadgeProps = ComponentProps; + +function renderBadgeRow( args: BadgeProps, overrides: Array<{ labelText: string; badge: BadgeProps }>, -) => ( -
- {overrides.map(({ labelText, badge }) => ( -
- {labelText} - -
- ))} -
-); +) { + return ( +
+ {overrides.map(({ labelText, badge }) => ( +
+ {labelText} + +
+ ))} +
+ ); +} export const Playground: Story = {}; @@ -122,14 +121,21 @@ export const SubtleColors: Story = { ), }; -export const FullMatrix: Story = { +export const AllCombinations: Story = { args: { label: '9' }, + argTypes: { + variant: { control: false }, + color: { control: false }, + size: { control: false }, + label: { control: false }, + }, render: (args) => (
{(['default', 'subtle'] as const).map((variant) => sizes.map((size) => (
{`${variant} / ${size}`} + {colors.map((color) => ( ))} + + {colors.map((color) => ( + + ))}
)), )} From da2a6751ff69ed9bffc33627f90fa7981a5a1d29 Mon Sep 17 00:00:00 2001 From: Sjur Sutterud Sagen Date: Thu, 7 May 2026 08:52:20 +0200 Subject: [PATCH 07/15] Enhance Badge component stories with color rendering functions and refactor for clarity and code deduplication --- .../lib/components/Badge/Badge.stories.tsx | 109 ++++++++---------- 1 file changed, 47 insertions(+), 62 deletions(-) diff --git a/packages/pxweb2-ui/src/lib/components/Badge/Badge.stories.tsx b/packages/pxweb2-ui/src/lib/components/Badge/Badge.stories.tsx index 6bca2305d..e7bdb060b 100644 --- a/packages/pxweb2-ui/src/lib/components/Badge/Badge.stories.tsx +++ b/packages/pxweb2-ui/src/lib/components/Badge/Badge.stories.tsx @@ -5,6 +5,7 @@ import { Badge } from './Badge'; const colors = ['neutral', 'info', 'success', 'warning', 'error'] as const; const sizes = ['medium', 'large'] as const; +const variants = ['default', 'subtle'] as const; const meta = { component: Badge, title: 'Components/Badge', @@ -43,14 +44,12 @@ const labelStyle = { type Story = StoryObj; type BadgeProps = ComponentProps; +type BadgeRow = { labelText: string; badge: BadgeProps }; -function renderBadgeRow( - args: BadgeProps, - overrides: Array<{ labelText: string; badge: BadgeProps }>, -) { +function renderBadgeRows(args: BadgeProps, rows: BadgeRow[]) { return (
- {overrides.map(({ labelText, badge }) => ( + {rows.map(({ labelText, badge }) => (
{labelText} @@ -60,11 +59,39 @@ function renderBadgeRow( ); } +function renderColorRow( + args: BadgeProps, + keyPrefix: string, + badge: BadgeProps, +) { + return ( +
+ {colors.map((color) => ( + + ))} +
+ ); +} + +function renderColorRows(args: BadgeProps, variant: 'default' | 'subtle') { + return ( +
+ {renderColorRow(args, `${variant}-labeled`, {})} + {renderColorRow(args, `${variant}-unlabeled`, { label: '' })} +
+ ); +} + export const Playground: Story = {}; export const SizeAndLabelStates: Story = { render: (args) => - renderBadgeRow(args, [ + renderBadgeRows(args, [ { labelText: 'Medium with label', badge: { size: 'medium', label: '9' } }, { labelText: 'Large with label', badge: { size: 'large', label: '99' } }, { @@ -77,48 +104,12 @@ export const SizeAndLabelStates: Story = { export const DefaultColors: Story = { args: { variant: 'default', label: '9', size: 'medium' }, - render: (args) => ( -
-
- {colors.map((color) => ( - - ))} -
-
- {colors.map((color) => ( - - ))} -
-
- ), + render: (args) => renderColorRows(args, 'default'), }; export const SubtleColors: Story = { args: { variant: 'subtle', label: '9', size: 'medium' }, - render: (args) => ( -
-
- {colors.map((color) => ( - - ))} -
-
- {colors.map((color) => ( - - ))} -
-
- ), + render: (args) => renderColorRows(args, 'subtle'), }; export const AllCombinations: Story = { @@ -131,29 +122,23 @@ export const AllCombinations: Story = { }, render: (args) => (
- {(['default', 'subtle'] as const).map((variant) => + {variants.map((variant) => sizes.map((size) => (
{`${variant} / ${size}`} - {colors.map((color) => ( - - ))} + {/* With label */} + {renderColorRow(args, `${variant}-${size}-labeled`, { + variant, + size, + })} - {colors.map((color) => ( - - ))} + {/* Without label */} + {renderColorRow(args, `${variant}-${size}-unlabeled`, { + variant, + size, + label: '', + })}
)), )} From 032dcd7cf9ec71ab7ed4b37adfa30e7cc7484976 Mon Sep 17 00:00:00 2001 From: Sjur Sutterud Sagen Date: Thu, 7 May 2026 12:54:37 +0200 Subject: [PATCH 08/15] Refactor Badge component stories to consolidate color rendering and improve clarity --- .../lib/components/Badge/Badge.stories.tsx | 49 ++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/packages/pxweb2-ui/src/lib/components/Badge/Badge.stories.tsx b/packages/pxweb2-ui/src/lib/components/Badge/Badge.stories.tsx index e7bdb060b..e9727dce3 100644 --- a/packages/pxweb2-ui/src/lib/components/Badge/Badge.stories.tsx +++ b/packages/pxweb2-ui/src/lib/components/Badge/Badge.stories.tsx @@ -78,15 +78,6 @@ function renderColorRow( ); } -function renderColorRows(args: BadgeProps, variant: 'default' | 'subtle') { - return ( -
- {renderColorRow(args, `${variant}-labeled`, {})} - {renderColorRow(args, `${variant}-unlabeled`, { label: '' })} -
- ); -} - export const Playground: Story = {}; export const SizeAndLabelStates: Story = { @@ -102,14 +93,38 @@ export const SizeAndLabelStates: Story = { ]), }; -export const DefaultColors: Story = { - args: { variant: 'default', label: '9', size: 'medium' }, - render: (args) => renderColorRows(args, 'default'), -}; - -export const SubtleColors: Story = { - args: { variant: 'subtle', label: '9', size: 'medium' }, - render: (args) => renderColorRows(args, 'subtle'), +export const ColorsByVariant: Story = { + args: { label: '9', size: 'medium' }, + argTypes: { + variant: { control: false }, + color: { control: false }, + }, + render: (args) => ( +
+
+ Default (with label) + {renderColorRow(args, 'default-labeled', { variant: 'default' })} +
+
+ Default (without label) + {renderColorRow(args, 'default-unlabeled', { + variant: 'default', + label: '', + })} +
+
+ Subtle (with label) + {renderColorRow(args, 'subtle-labeled', { variant: 'subtle' })} +
+
+ Subtle (without label) + {renderColorRow(args, 'subtle-unlabeled', { + variant: 'subtle', + label: '', + })} +
+
+ ), }; export const AllCombinations: Story = { From 0122cf7ad969a79d342d9e22f8dfb625516f3f9b Mon Sep 17 00:00:00 2001 From: Sjur Sutterud Sagen Date: Thu, 7 May 2026 12:54:52 +0200 Subject: [PATCH 09/15] Refactor Tag component to use color and variant props, update styles and tests for consistency --- .../lib/components/TableCard/TableCard.tsx | 5 +- .../src/lib/components/Tag/Tag.module.scss | 72 +++---- .../src/lib/components/Tag/Tag.spec.tsx | 96 +++++++++- .../src/lib/components/Tag/Tag.stories.tsx | 181 +++++++++++------- .../pxweb2-ui/src/lib/components/Tag/Tag.tsx | 33 ++-- .../VariableBoxHeader/VariableBoxHeader.tsx | 4 +- 6 files changed, 253 insertions(+), 138 deletions(-) diff --git a/packages/pxweb2-ui/src/lib/components/TableCard/TableCard.tsx b/packages/pxweb2-ui/src/lib/components/TableCard/TableCard.tsx index 834d8d52a..b3bdbd019 100644 --- a/packages/pxweb2-ui/src/lib/components/TableCard/TableCard.tsx +++ b/packages/pxweb2-ui/src/lib/components/TableCard/TableCard.tsx @@ -97,7 +97,8 @@ export const TableCard = forwardRef(
{frequency} @@ -113,7 +114,7 @@ export const TableCard = forwardRef( )}
{tableId && ( - + {tableId} )} diff --git a/packages/pxweb2-ui/src/lib/components/Tag/Tag.module.scss b/packages/pxweb2-ui/src/lib/components/Tag/Tag.module.scss index 7ca48d671..7fdf93200 100644 --- a/packages/pxweb2-ui/src/lib/components/Tag/Tag.module.scss +++ b/packages/pxweb2-ui/src/lib/components/Tag/Tag.module.scss @@ -1,4 +1,3 @@ -@use '../../../../style-dictionary/dist/scss/fixed-variables.scss' as fixed; @use '../../text-styles.scss'; .tag { @@ -7,85 +6,88 @@ align-items: center; } -.medium { +.size-medium { min-height: 32px; padding: 5px 8px 4px 8px; border-radius: var(--px-border-radius-small); } -.small { +.size-small { min-height: 24px; padding: 2px 4px 2px 4px; border-radius: var(--px-border-radius-xsmall); - &.border { + + &.variant-border { padding: 1px 4px 2px 4px; } } -.xsmall { +.size-xsmall { min-height: 20px; padding: 2px 4px 0px; border-radius: var(--px-border-radius-xsmall); -} -.subtle { - background-color: var(--px-color-surface-subtle); - &.border { - background-color: var(--px-color-surface-default); - outline: 1px solid var(--px-color-border-subtle); - outline-offset: -1px; + &.variant-border { + padding: 1px 4px 0px; } } -.neutral { - background-color: var(--px-color-surface-moderate); - &.border { +.color-neutral { + &.variant-default { + background-color: var(--px-color-surface-moderate); + } + + &.variant-border { background-color: var(--px-color-surface-subtle); outline: 1px solid var(--px-color-border-moderate); outline-offset: -1px; } } -.info { - background-color: var(--px-color-surface-info-moderate); - &.border { +.color-info { + &.variant-default { + background-color: var(--px-color-surface-info-moderate); + } + + &.variant-border { background-color: var(--px-color-surface-info-subtle); outline: 1px solid var(--px-color-border-info); outline-offset: -1px; } } -.success { - background-color: var(--px-color-surface-success-moderate); - &.border { +.color-success { + &.variant-default { + background-color: var(--px-color-surface-success-moderate); + } + + &.variant-border { background-color: var(--px-color-surface-success-subtle); outline: 1px solid var(--px-color-border-success); outline-offset: -1px; } } -.warning { - background-color: var(--px-color-surface-warning-moderate); - &.border { +.color-warning { + &.variant-default { + background-color: var(--px-color-surface-warning-moderate); + } + + &.variant-border { background-color: var(--px-color-surface-warning-subtle); outline: 1px solid var(--px-color-border-warning); outline-offset: -1px; } } -.error { - background-color: var(--px-color-surface-error-moderate); - &.border { +.color-error { + &.variant-default { + background-color: var(--px-color-surface-error-moderate); + } + + &.variant-border { background-color: var(--px-color-surface-error-subtle); outline: 1px solid var(--px-color-border-error); outline-offset: -1px; } } - -.error-subtle { - background-color: var(--px-color-surface-error-subtle); -} - -.default { - border: none; -} diff --git a/packages/pxweb2-ui/src/lib/components/Tag/Tag.spec.tsx b/packages/pxweb2-ui/src/lib/components/Tag/Tag.spec.tsx index 6b9719cdb..a1a08cfa7 100644 --- a/packages/pxweb2-ui/src/lib/components/Tag/Tag.spec.tsx +++ b/packages/pxweb2-ui/src/lib/components/Tag/Tag.spec.tsx @@ -1,10 +1,96 @@ -import { render } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom/vitest'; -import Tag from './Tag'; +import { Tag } from './Tag'; +import classes from './Tag.module.scss'; describe('Tag', () => { - it('should render successfully', () => { - const { baseElement } = render(); - expect(baseElement).toBeTruthy(); + it('renders default classes when no props are provided', () => { + const { container } = render(); + const tag = container.firstElementChild as HTMLElement; + + expect(tag).toHaveClass(classes.tag); + expect(tag).toHaveClass(classes['variant-default']); + expect(tag).toHaveClass(classes['color-neutral']); + expect(tag).toHaveClass(classes['size-medium']); + expect(tag).toHaveClass(classes['label-medium']); + }); + + it('renders children when provided', () => { + render(Tag text); + + expect(screen.getByText('Tag text')).toBeInTheDocument(); + }); + + it('applies selected variant, color, and size classes', () => { + const { container } = render( + + Tag + , + ); + const tag = container.firstElementChild as HTMLElement; + + expect(tag).toHaveClass(classes['variant-border']); + expect(tag).toHaveClass(classes['color-error']); + expect(tag).toHaveClass(classes['size-small']); + expect(tag).toHaveClass(classes['label-small']); + }); + + it('passes through HTML span attributes and merges className', () => { + render( + + Tag + , + ); + + const tag = screen.getByTestId('tag-element'); + expect(tag).toHaveAttribute('title', 'tag-title'); + expect(tag).toHaveAttribute('aria-label', 'tag-aria'); + expect(tag).toHaveClass('custom-tag'); + }); + + it.each(['neutral', 'info', 'success', 'warning', 'error'] as const)( + 'applies color class for %s', + (color) => { + const { container } = render(Tag); + const tag = container.firstElementChild as HTMLElement; + + expect(tag).toHaveClass(classes[`color-${color}`]); + }, + ); + + it.each(['default', 'border'] as const)( + 'applies variant class for %s', + (variant) => { + const { container } = render(Tag); + const tag = container.firstElementChild as HTMLElement; + + expect(tag).toHaveClass(classes[`variant-${variant}`]); + }, + ); + + it.each(['medium', 'small', 'xsmall'] as const)( + 'applies size class for %s', + (size) => { + const { container } = render(Tag); + const tag = container.firstElementChild as HTMLElement; + + expect(tag).toHaveClass(classes[`size-${size}`]); + }, + ); + + it('uses label-medium for medium and label-small for non-medium sizes', () => { + const { container: mediumContainer } = render(Tag); + const mediumTag = mediumContainer.firstElementChild as HTMLElement; + expect(mediumTag).toHaveClass(classes['label-medium']); + + const { container: smallContainer } = render(Tag); + const smallTag = smallContainer.firstElementChild as HTMLElement; + expect(smallTag).toHaveClass(classes['label-small']); }); }); diff --git a/packages/pxweb2-ui/src/lib/components/Tag/Tag.stories.tsx b/packages/pxweb2-ui/src/lib/components/Tag/Tag.stories.tsx index 7eed57355..bc7c4be33 100644 --- a/packages/pxweb2-ui/src/lib/components/Tag/Tag.stories.tsx +++ b/packages/pxweb2-ui/src/lib/components/Tag/Tag.stories.tsx @@ -1,99 +1,132 @@ -import type { Meta, StoryFn } from '@storybook/react-vite'; +import type { ComponentProps } from 'react'; +import type { Meta, StoryObj } from '@storybook/react-vite'; + import { Tag } from './Tag'; -const meta: Meta = { +const colors = ['neutral', 'info', 'success', 'warning', 'error'] as const; +const sizes = ['medium', 'small', 'xsmall'] as const; +const variants = ['default', 'border'] as const; + +const meta = { component: Tag, title: 'Components/Tag', -}; -export default meta; - -const text = 'Tag'; - -export const Default = { + tags: ['autodocs'], args: { size: 'medium', - variant: 'neutral', - type: 'default', - children: text, + variant: 'default', + color: 'neutral', + children: 'Tag', }, argTypes: { - size: { - options: ['medium', 'small', 'xsmall'], - control: { type: 'radio' }, - }, + size: { control: 'inline-radio', options: ['medium', 'small', 'xsmall'] }, variant: { - options: [ - 'neutral', - 'subtle', - 'info', - 'success', - 'warning', - 'error', - 'error-subtle', - ], - control: { type: 'radio' }, - }, - type: { + control: 'inline-radio', options: ['default', 'border'], - control: { type: 'radio' }, }, + color: { + control: 'inline-radio', + options: ['neutral', 'info', 'success', 'warning', 'error'], + }, + children: { control: 'text' }, }, -}; +} satisfies Meta; -export const Size: StoryFn = () => { - return ( - <> -

Size

+const wrapperStyle = { + display: 'flex', + flexDirection: 'column', + gap: '16px', +} as const; -

default:

- {text} +const rowStyle = { + display: 'flex', + alignItems: 'center', + gap: '12px', + flexWrap: 'wrap', +} as const; -

medium:

- {text} +const labelStyle = { + minWidth: '150px', + fontWeight: 600, +} as const; -

small:

- {text} +type Story = StoryObj; +type TagProps = ComponentProps; +type TagRow = { labelText: string; tag: TagProps }; -

xsmall:

- {text} - +function renderTagRows(args: TagProps, rows: TagRow[]) { + return ( +
+ {rows.map(({ labelText, tag }) => ( +
+ {labelText} + +
+ ))} +
); -}; +} -export const Variant: StoryFn = () => { +function renderColorRow(args: TagProps, keyPrefix: string, tag: TagProps) { return ( - <> -

Variant

-

default:

- {text} -

subtle:

- {text} -

neutral:

- {text} -

info:

- {text} -

success:

- {text} -

warning:

- {text} -

error:

- {text} -

error-subtle:

- {text} - +
+ {colors.map((color) => ( + + ))} +
); -}; +} -export const Type: StoryFn = () => { - return ( - <> -

Type

+export const Playground: Story = {}; -

default:

- {text} +export const SizeStates: Story = { + render: (args) => + renderTagRows(args, [ + { labelText: 'Medium', tag: { size: 'medium' } }, + { labelText: 'Small', tag: { size: 'small' } }, + { labelText: 'Xsmall', tag: { size: 'xsmall' } }, + ]), +}; -

border:

- {text} - - ); +export const ColorsByVariant: Story = { + args: { children: 'Tag', size: 'medium' }, + argTypes: { + variant: { control: false }, + color: { control: false }, + }, + render: (args) => ( +
+
+ Default + {renderColorRow(args, 'default', { variant: 'default' })} +
+
+ Border + {renderColorRow(args, 'border', { variant: 'border' })} +
+
+ ), }; + +export const AllCombinations: Story = { + args: { children: 'Tag' }, + argTypes: { + variant: { control: false }, + color: { control: false }, + size: { control: false }, + children: { control: false }, + }, + render: (args) => ( +
+ {variants.map((variant) => + sizes.map((size) => ( +
+ {`${variant} / ${size}`} + {renderColorRow(args, `${variant}-${size}`, { variant, size })} +
+ )), + )} +
+ ), +}; + +export default meta; diff --git a/packages/pxweb2-ui/src/lib/components/Tag/Tag.tsx b/packages/pxweb2-ui/src/lib/components/Tag/Tag.tsx index 0f1993570..f8f1edc46 100644 --- a/packages/pxweb2-ui/src/lib/components/Tag/Tag.tsx +++ b/packages/pxweb2-ui/src/lib/components/Tag/Tag.tsx @@ -1,40 +1,33 @@ -import cl from 'clsx'; +import clsx from 'clsx'; import classes from './Tag.module.scss'; export interface TagProps extends React.HTMLAttributes { size?: 'medium' | 'small' | 'xsmall'; - variant?: - | 'neutral' - | 'info' - | 'success' - | 'warning' - | 'error' - | 'subtle' - | 'error-subtle'; - type?: 'default' | 'border'; + variant?: 'default' | 'border'; + color?: 'neutral' | 'info' | 'success' | 'warning' | 'error'; children?: React.ReactNode; } export function Tag({ size = 'medium', - variant = 'neutral', - type = 'default', + variant = 'default', + color = 'neutral', children, + className, ...rest }: TagProps) { - let textStyle = 'label-small'; - if (size === 'medium') { - textStyle = 'label-medium'; - } + const textStyle = size === 'medium' ? 'label-medium' : 'label-small'; + return ( diff --git a/packages/pxweb2-ui/src/lib/components/VariableBox/VariableBoxHeader/VariableBoxHeader.tsx b/packages/pxweb2-ui/src/lib/components/VariableBox/VariableBoxHeader/VariableBoxHeader.tsx index ce04cf8e9..d57c7d562 100644 --- a/packages/pxweb2-ui/src/lib/components/VariableBox/VariableBoxHeader/VariableBoxHeader.tsx +++ b/packages/pxweb2-ui/src/lib/components/VariableBox/VariableBoxHeader/VariableBoxHeader.tsx @@ -69,7 +69,7 @@ export function VariableBoxHeader({ {label}
- + {t( 'presentation_page.side_menu.selection.variablebox.header.tag_selected', { @@ -83,7 +83,7 @@ export function VariableBoxHeader({ )} {mandatory && ( - + {t( 'presentation_page.side_menu.selection.variablebox.header.tag_mandatory', )} From cf1e7d9bd3cfb06ef3759d7f7aca4a7805ba768e Mon Sep 17 00:00:00 2001 From: Sjur Sutterud Sagen Date: Thu, 7 May 2026 13:06:17 +0200 Subject: [PATCH 10/15] Add missing subtle color variant for Tag component --- .../pxweb2-ui/src/lib/components/Tag/Tag.module.scss | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/pxweb2-ui/src/lib/components/Tag/Tag.module.scss b/packages/pxweb2-ui/src/lib/components/Tag/Tag.module.scss index 7fdf93200..34cf38191 100644 --- a/packages/pxweb2-ui/src/lib/components/Tag/Tag.module.scss +++ b/packages/pxweb2-ui/src/lib/components/Tag/Tag.module.scss @@ -32,6 +32,18 @@ } } +.color-subtle { + &.variant-default { + background-color: var(--px-color-surface-subtle); + } + + &.variant-border { + background-color: var(--px-color-surface-default); + outline: 1px solid var(--px-color-border-subtle); + outline-offset: -1px; + } +} + .color-neutral { &.variant-default { background-color: var(--px-color-surface-moderate); From 37daa41d68178cb3c5e345d5fdba7ed14eb45965 Mon Sep 17 00:00:00 2001 From: Sjur Sutterud Sagen Date: Thu, 7 May 2026 13:16:02 +0200 Subject: [PATCH 11/15] Add 'subtle' color option to Tag component and update stories for color rendering --- .../src/lib/components/Tag/Tag.stories.tsx | 13 +++++++++++-- packages/pxweb2-ui/src/lib/components/Tag/Tag.tsx | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/pxweb2-ui/src/lib/components/Tag/Tag.stories.tsx b/packages/pxweb2-ui/src/lib/components/Tag/Tag.stories.tsx index bc7c4be33..d1800789c 100644 --- a/packages/pxweb2-ui/src/lib/components/Tag/Tag.stories.tsx +++ b/packages/pxweb2-ui/src/lib/components/Tag/Tag.stories.tsx @@ -3,7 +3,14 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; import { Tag } from './Tag'; -const colors = ['neutral', 'info', 'success', 'warning', 'error'] as const; +const colors = [ + 'subtle', + 'neutral', + 'info', + 'success', + 'warning', + 'error', +] as const; const sizes = ['medium', 'small', 'xsmall'] as const; const variants = ['default', 'border'] as const; @@ -70,7 +77,9 @@ function renderColorRow(args: TagProps, keyPrefix: string, tag: TagProps) { return (
{colors.map((color) => ( - + + {color} + ))}
); diff --git a/packages/pxweb2-ui/src/lib/components/Tag/Tag.tsx b/packages/pxweb2-ui/src/lib/components/Tag/Tag.tsx index f8f1edc46..29af942bf 100644 --- a/packages/pxweb2-ui/src/lib/components/Tag/Tag.tsx +++ b/packages/pxweb2-ui/src/lib/components/Tag/Tag.tsx @@ -5,7 +5,7 @@ import classes from './Tag.module.scss'; export interface TagProps extends React.HTMLAttributes { size?: 'medium' | 'small' | 'xsmall'; variant?: 'default' | 'border'; - color?: 'neutral' | 'info' | 'success' | 'warning' | 'error'; + color?: 'subtle' | 'neutral' | 'info' | 'success' | 'warning' | 'error'; children?: React.ReactNode; } From 703fa3ba2c49bd2f1878a4ef220e8a837735a104 Mon Sep 17 00:00:00 2001 From: Sjur Sutterud Sagen Date: Thu, 7 May 2026 13:31:53 +0200 Subject: [PATCH 12/15] fix TableCard using wrong tag color --- packages/pxweb2-ui/src/lib/components/TableCard/TableCard.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/pxweb2-ui/src/lib/components/TableCard/TableCard.tsx b/packages/pxweb2-ui/src/lib/components/TableCard/TableCard.tsx index b3bdbd019..fe71cbef6 100644 --- a/packages/pxweb2-ui/src/lib/components/TableCard/TableCard.tsx +++ b/packages/pxweb2-ui/src/lib/components/TableCard/TableCard.tsx @@ -97,7 +97,7 @@ export const TableCard = forwardRef(
{frequency} @@ -114,7 +114,7 @@ export const TableCard = forwardRef( )}
{tableId && ( - + {tableId} )} From a03315e76a7ddd4615b989bb877368199d0c6e59 Mon Sep 17 00:00:00 2001 From: Sjur Sutterud Sagen Date: Thu, 7 May 2026 14:43:25 +0200 Subject: [PATCH 13/15] Add 'error-subtle' color variant to Tag component and update TableCard usage --- .../pxweb2-ui/src/lib/components/TableCard/TableCard.tsx | 2 +- .../pxweb2-ui/src/lib/components/Tag/Tag.module.scss | 5 +++++ .../pxweb2-ui/src/lib/components/Tag/Tag.stories.tsx | 1 + packages/pxweb2-ui/src/lib/components/Tag/Tag.tsx | 9 ++++++++- 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/pxweb2-ui/src/lib/components/TableCard/TableCard.tsx b/packages/pxweb2-ui/src/lib/components/TableCard/TableCard.tsx index fe71cbef6..ff22298f0 100644 --- a/packages/pxweb2-ui/src/lib/components/TableCard/TableCard.tsx +++ b/packages/pxweb2-ui/src/lib/components/TableCard/TableCard.tsx @@ -97,7 +97,7 @@ export const TableCard = forwardRef(
{frequency} diff --git a/packages/pxweb2-ui/src/lib/components/Tag/Tag.module.scss b/packages/pxweb2-ui/src/lib/components/Tag/Tag.module.scss index 34cf38191..8b72c3c58 100644 --- a/packages/pxweb2-ui/src/lib/components/Tag/Tag.module.scss +++ b/packages/pxweb2-ui/src/lib/components/Tag/Tag.module.scss @@ -103,3 +103,8 @@ outline-offset: -1px; } } + +/* Subtle error variant without border. Looks the same in both default and border variants. */ +.color-error-subtle { + background-color: var(--px-color-surface-error-subtle); +} diff --git a/packages/pxweb2-ui/src/lib/components/Tag/Tag.stories.tsx b/packages/pxweb2-ui/src/lib/components/Tag/Tag.stories.tsx index d1800789c..6d1c1fd59 100644 --- a/packages/pxweb2-ui/src/lib/components/Tag/Tag.stories.tsx +++ b/packages/pxweb2-ui/src/lib/components/Tag/Tag.stories.tsx @@ -10,6 +10,7 @@ const colors = [ 'success', 'warning', 'error', + 'error-subtle', ] as const; const sizes = ['medium', 'small', 'xsmall'] as const; const variants = ['default', 'border'] as const; diff --git a/packages/pxweb2-ui/src/lib/components/Tag/Tag.tsx b/packages/pxweb2-ui/src/lib/components/Tag/Tag.tsx index 29af942bf..26e0b3a53 100644 --- a/packages/pxweb2-ui/src/lib/components/Tag/Tag.tsx +++ b/packages/pxweb2-ui/src/lib/components/Tag/Tag.tsx @@ -5,7 +5,14 @@ import classes from './Tag.module.scss'; export interface TagProps extends React.HTMLAttributes { size?: 'medium' | 'small' | 'xsmall'; variant?: 'default' | 'border'; - color?: 'subtle' | 'neutral' | 'info' | 'success' | 'warning' | 'error'; + color?: + | 'subtle' + | 'neutral' + | 'info' + | 'success' + | 'warning' + | 'error' + | 'error-subtle'; children?: React.ReactNode; } From a169fa15c58aef30a10e9b2790f5be45f07f950a Mon Sep 17 00:00:00 2001 From: Sjur Sutterud Sagen Date: Fri, 8 May 2026 10:44:33 +0200 Subject: [PATCH 14/15] Add Badge components to index export --- packages/pxweb2-ui/src/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/pxweb2-ui/src/index.ts b/packages/pxweb2-ui/src/index.ts index 3c8afc3f1..67870127e 100644 --- a/packages/pxweb2-ui/src/index.ts +++ b/packages/pxweb2-ui/src/index.ts @@ -1,6 +1,7 @@ export * from './../style-dictionary/dist/js/css-variables'; export * from './../style-dictionary/dist/js/fixed-variables'; export * from './lib/components/ActionItem/ActionItem'; +export * from './lib/components/Badge/Badge'; export * from './lib/components/BottomSheet/BottomSheet'; export * from './lib/components/Breadcrumbs/Breadcrumbs'; export * from './lib/components/Button/Button'; @@ -22,6 +23,7 @@ export * from './lib/components/Link/Link'; export * from './lib/components/LinkCard/LinkCard'; export * from './lib/components/List'; export * from './lib/components/LocalAlert/LocalAlert'; +export * from './lib/components/MarkdownRenderer/MarkdownRenderer'; export * from './lib/components/Notes/MandatoryNotes'; export * from './lib/components/Notes/MandatoryTableNotes'; export * from './lib/components/Notes/MandatoryVariableNotes'; @@ -51,7 +53,6 @@ export * from './lib/components/Typography/Ingress/Ingress'; export * from './lib/components/Typography/Label/Label'; export * from './lib/components/VariableBox/VariableBox'; export * from './lib/components/VariableList/VariableList'; -export * from './lib/components/MarkdownRenderer/MarkdownRenderer'; export * from './lib/shared-types/codelist'; export * from './lib/shared-types/contact'; export * from './lib/shared-types/contentInfo'; From de01f1bfcc168ef13c3164cf12e91feb3d59415b Mon Sep 17 00:00:00 2001 From: Sjur Sutterud Sagen Date: Mon, 11 May 2026 14:11:39 +0200 Subject: [PATCH 15/15] Fix Badge component to use span instead of div and update no-label test --- packages/pxweb2-ui/src/lib/components/Badge/Badge.spec.tsx | 2 +- packages/pxweb2-ui/src/lib/components/Badge/Badge.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/pxweb2-ui/src/lib/components/Badge/Badge.spec.tsx b/packages/pxweb2-ui/src/lib/components/Badge/Badge.spec.tsx index 9cae54dd9..eb8386536 100644 --- a/packages/pxweb2-ui/src/lib/components/Badge/Badge.spec.tsx +++ b/packages/pxweb2-ui/src/lib/components/Badge/Badge.spec.tsx @@ -29,7 +29,7 @@ describe('Badge', () => { const { container } = render(); const badge = container.firstElementChild as HTMLElement; - expect(container.querySelector('span')).toBeNull(); + expect(container.querySelector(`.${classes['label-medium']}`)).toBeNull(); expect(badge).toHaveClass(classes['no-label']); }); diff --git a/packages/pxweb2-ui/src/lib/components/Badge/Badge.tsx b/packages/pxweb2-ui/src/lib/components/Badge/Badge.tsx index 5158388f3..739353c5c 100644 --- a/packages/pxweb2-ui/src/lib/components/Badge/Badge.tsx +++ b/packages/pxweb2-ui/src/lib/components/Badge/Badge.tsx @@ -18,7 +18,7 @@ export function Badge({ const withoutLabel = !label || label.trim() === ''; return ( -
{label && {label}} -
+ ); }