style: refactor Button and numericStepper components for improved accessibility and styling
This commit is contained in:
@@ -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;
|
||||||
&__primary {
|
user-select: none;
|
||||||
background-color: var(--nds-primary);
|
transition:
|
||||||
color: var(--nds-text);
|
background-color 140ms ease,
|
||||||
&:hover:not(.button--disabled) {
|
border-color 140ms ease,
|
||||||
background-color: var(--nds-secondary);
|
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) {
|
&:active:not(.button--disabled) {
|
||||||
background-color: var(--nds-accent);
|
transform: translateY(0.5px);
|
||||||
color: var(--nds-background);
|
}
|
||||||
|
&--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 {
|
||||||
|
background-color: var(--nds-primary);
|
||||||
|
color: var(--nds-on-primary);
|
||||||
|
border-color: var(--nds-primary);
|
||||||
|
&:hover:not(.button--disabled) {
|
||||||
|
background-color: color-mix(in srgb, var(--nds-primary) 88%, #000);
|
||||||
|
border-color: color-mix(in srgb, var(--nds-primary) 88%, #000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&__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;
|
||||||
&--icon {
|
box-shadow: none;
|
||||||
padding: var(--nds-spacing-2xs) var(--nds-spacing-xs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,44 @@
|
|||||||
---
|
---
|
||||||
export interface Props {
|
export interface Props {
|
||||||
type: 'primary' | 'secondary';
|
type?: 'primary' | 'secondary' | 'ghost' | 'danger';
|
||||||
|
size?: 'sm' | 'md' | 'lg';
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
icon?: 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';
|
||||||
|
|||||||
@@ -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>
|
||||||
Reference in New Issue
Block a user