style: refactor Button and numericStepper components for improved accessibility and styling

This commit is contained in:
2026-06-23 10:07:39 +02:00
parent b2f4cfe393
commit cc54ae46ff
4 changed files with 162 additions and 46 deletions
+78 -21
View File
@@ -1,40 +1,97 @@
@use '../../styles/tokens/typography' as *; @use "../../styles/tokens/typography" as *;
.button { .button {
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--nds-spacing-xs);
width: fit-content; width: fit-content;
padding: var(--nds-spacing-sm) var(--nds-spacing-md); border: var(--nds-border-width-thin) solid transparent;
border-radius: var(--nds-radius-sm); border-radius: var(--nds-radius-md);
@include text-base; @include text-label;
text-decoration: none;
white-space: nowrap;
cursor: pointer; cursor: pointer;
user-select: none;
transition:
background-color 140ms ease,
border-color 140ms ease,
color 140ms ease,
box-shadow 140ms ease,
transform 80ms ease;
&:focus-visible {
outline: none;
box-shadow: 0 0 0 3px var(--nds-ring);
}
&:active:not(.button--disabled) {
transform: translateY(0.5px);
}
&--sm {
height: 30px;
padding: 0 var(--nds-spacing-sm);
}
&--md {
height: 38px;
padding: 0 var(--nds-spacing-md);
}
&--lg {
height: 46px;
padding: 0 var(--nds-spacing-lg);
font-size: 0.9375rem;
}
&--icon {
padding: 0;
aspect-ratio: 1;
}
&--icon.button--sm {
width: 30px;
}
&--icon.button--md {
width: 38px;
}
&--icon.button--lg {
width: 46px;
}
&__primary { &__primary {
background-color: var(--nds-primary); background-color: var(--nds-primary);
color: var(--nds-text); color: var(--nds-on-primary);
border-color: var(--nds-primary);
&:hover:not(.button--disabled) { &:hover:not(.button--disabled) {
background-color: var(--nds-secondary); background-color: color-mix(in srgb, var(--nds-primary) 88%, #000);
} border-color: color-mix(in srgb, var(--nds-primary) 88%, #000);
&:active:not(.button--disabled) {
background-color: var(--nds-accent);
color: var(--nds-background);
} }
} }
&__secondary { &__secondary {
border: var(--nds-border-width-medium) solid; background-color: transparent;
border-color: var(--nds-primary);
color: var(--nds-primary); color: var(--nds-primary);
border-color: var(--nds-border-strong);
&:hover:not(.button--disabled) { &:hover:not(.button--disabled) {
border-color: var(--nds-secondary); border-color: var(--nds-primary);
background-color: var(--nds-primary-soft);
} }
&:active:not(.button--disabled) { }
border-color: var(--nds-accent); &__ghost {
color: var(--nds-accent); background-color: transparent;
color: var(--nds-text);
border-color: transparent;
&:hover:not(.button--disabled) {
background-color: var(--nds-surface-hover);
}
}
&__danger {
background-color: var(--nds-error-medium);
color: #fff;
border-color: var(--nds-error-medium);
&:hover:not(.button--disabled) {
background-color: color-mix(in srgb, var(--nds-error-medium) 88%, #000);
border-color: color-mix(in srgb, var(--nds-error-medium) 88%, #000);
} }
} }
&--disabled { &--disabled {
cursor: not-allowed; cursor: not-allowed;
background-color: var(--nds-disabled); background-color: var(--nds-disabled);
color: var(--nds-neutral); color: var(--nds-neutral);
border-color: transparent;
box-shadow: none;
} }
&--icon { }
padding: var(--nds-spacing-2xs) var(--nds-spacing-xs);
}
}
+37 -8
View File
@@ -1,16 +1,45 @@
--- ---
export interface Props { export interface Props {
type: 'primary' | 'secondary'; type?: 'primary' | 'secondary' | 'ghost' | 'danger';
disabled?: boolean; size?: 'sm' | 'md' | 'lg';
icon?: boolean; disabled?: boolean;
icon?: boolean;
href?: string;
htmlType?: 'button' | 'submit' | 'reset';
} }
const { type, disabled = false, icon = false } = Astro.props; const {
type = 'primary',
size = 'md',
disabled = false,
icon = false,
href,
htmlType = 'button',
...rest
} = Astro.props;
const classes = [
'button',
`button__${type}`,
`button--${size}`,
icon ? 'button--icon' : '',
disabled ? 'button--disabled' : '',
].filter(Boolean).join(' ');
const Tag = href ? 'a' : 'button';
--- ---
<div class={`button button__${type} ${disabled ? 'button--disabled' : ''} ${icon ? 'button--icon' : ''}`}> <Tag
<slot/> class={classes}
</div> href={href}
type={href ? undefined : htmlType}
aria-disabled={disabled ? 'true' : undefined}
{...rest}
>
<slot name="icon-left" />
<slot />
<slot name="icon-right" />
</Tag>
<style lang="scss"> <style lang="scss">
@use './_button.scss'; @use './_button.scss';
</style> </style>
@@ -1,14 +1,44 @@
@use '../../styles/tokens/typography' as *; @use "../../styles/tokens/typography" as *;
.numeric-stepper { .numeric-stepper {
display: flex; display: inline-flex;
flex-direction: column;
align-items: center; align-items: center;
gap: var(--nds-spacing-xs); gap: 0;
border: var(--nds-border-width-thin) solid var(--nds-border-strong);
border-radius: var(--nds-radius-md);
background-color: var(--nds-surface);
overflow: hidden;
width: fit-content; width: fit-content;
& p { height: fit-content;
@include text-xl;
margin: 0; &__button {
width: 36px;
height: 36px;
display: inline-flex;
align-items: center;
justify-content: center;
background: transparent;
border: none;
cursor: pointer;
color: var(--nds-text);
transition: background-color 120ms ease;
&:hover:not(:disabled) {
background-color: var(--nds-surface-hover);
}
&:disabled {
color: var(--nds-disabled);
cursor: not-allowed;
}
} }
} &__value {
width: 48px;
text-align: center;
@include text-label;
color: var(--nds-text);
padding: 0;
margin: 0;
border: none;
outline: none;
background: transparent;
}
}
@@ -1,6 +1,6 @@
--- ---
import Button from '../Button/button.astro'; import Button from '../Button/button.astro';
import { Arrow2Icon } from '../Icons'; import { MinusIcon, PlusIcon } from '../Icons';
export interface Props { export interface Props {
id: string; id: string;
@@ -23,16 +23,16 @@ const { id, min, max, value = 0, step = 1 } = Astro.props;
data-step={step} data-step={step}
> >
<span class="numeric-stepper__control" data-action="increment"> <span class="numeric-stepper__control" data-action="increment">
<Button type="secondary" icon={true}> <Button type="ghost" icon={true}>
<Arrow2Icon size={24} orientation="up" /> <MinusIcon size={24} />
</Button> </Button>
</span> </span>
<p class="numeric-stepper__value">{value}</p> <p class="numeric-stepper__value">{value}</p>
<span class="numeric-stepper__control" data-action="decrement"> <span class="numeric-stepper__control" data-action="decrement">
<Button type="secondary" icon={true}> <Button type="ghost" icon={true}>
<Arrow2Icon size={24} orientation="down" /> <PlusIcon size={24} />
</Button> </Button>
</span> </span>
</div> </div>
@@ -113,5 +113,5 @@ const { id, min, max, value = 0, step = 1 } = Astro.props;
</script> </script>
<style lang="scss"> <style lang="scss">
@use './numericStepper'; @use "./numericStepper";
</style> </style>