|
3 | 3 | :type="type" |
4 | 4 | :disabled="isButtonDisabled" |
5 | 5 | :aria-busy="ariaBusy" |
6 | | - :class="[$style.button, { |
| 6 | + :class="[$style.component, { |
7 | 7 | small: isSmallSize, |
8 | | - iconOnly: isIconOnlySize, |
9 | | - iconSmall: isIconSmallSize, |
10 | 8 | secondary: isSecondaryVariant, |
11 | | - ghost: isGhostVariant, |
12 | 9 | danger: isDangerVariant |
13 | 10 | }]" |
14 | 11 | > |
|
42 | 39 | icon?: string; |
43 | 40 | iconRight?: string; |
44 | 41 | loading?: boolean; |
45 | | - size?: 'medium' | 'small' | 'icon-only' | 'icon-small'; |
| 42 | + size?: 'medium' | 'small'; |
46 | 43 | type?: 'button' | 'reset' | 'submit'; |
47 | | - variant?: 'primary' | 'secondary' | 'ghost' | 'danger'; |
| 44 | + variant?: 'primary' | 'secondary' | 'danger'; |
48 | 45 | } |
49 | 46 |
|
50 | 47 | const { |
|
59 | 56 | const ariaBusy = computed(() => loading || undefined) |
60 | 57 | const isButtonDisabled = computed(() => disabled || loading) |
61 | 58 | const isSmallSize = computed(() => size === 'small') |
62 | | - const isIconOnlySize = computed(() => size === 'icon-only') |
63 | | - const isIconSmallSize = computed(() => size === 'icon-small') |
64 | 59 | const isSecondaryVariant = computed(() => variant === 'secondary') |
65 | | - const isGhostVariant = computed(() => variant === 'ghost') |
66 | 60 | const isDangerVariant = computed(() => variant === 'danger') |
67 | 61 | const rightIconName = computed(() => iconRight ?? '') |
68 | 62 | const showRightIcon = computed(() => iconRight !== undefined && iconRight !== '' && loading === false) |
69 | 63 | </script> |
70 | 64 |
|
71 | 65 | <style module> |
72 | | - .button { |
| 66 | + .component { |
73 | 67 | appearance: none; |
74 | 68 | border: 1px solid transparent; |
75 | 69 | cursor: pointer; |
76 | 70 | display: inline-flex; |
77 | 71 | align-items: center; |
78 | 72 | justify-content: center; |
79 | 73 | gap: var(--spacing-8); |
80 | | - height: 2.5rem; |
81 | | - padding: 0 var(--spacing-16); |
| 74 | + block-size: 2.5rem; |
| 75 | + padding-inline: var(--spacing-16); |
82 | 76 | border-radius: var(--border-radius-16); |
83 | 77 | background: var(--color-accent-base); |
84 | 78 | color: var(--color-accent-contrast); |
85 | | - outline: none; |
| 79 | + outline: 2px solid transparent; |
| 80 | + outline-offset: 3px; |
86 | 81 | user-select: none; |
87 | 82 | white-space: nowrap; |
88 | 83 | font-weight: var(--font-weight-medium); |
|
93 | 88 | color var(--transition-duration-quick) var(--transition-easing-out), |
94 | 89 | transform var(--transition-duration-quick) var(--transition-easing-out); |
95 | 90 |
|
96 | | - &:focus-visible, |
97 | 91 | &:hover { |
98 | 92 | background: var(--color-accent-hover); |
99 | 93 | } |
100 | 94 |
|
| 95 | + &:focus-visible { |
| 96 | + background: var(--color-accent-hover); |
| 97 | + outline-color: var(--color-accent-ring); |
| 98 | + } |
| 99 | +
|
101 | 100 | &:active { |
102 | 101 | transform: translateY(1px); |
103 | 102 | background: var(--color-accent-active); |
104 | 103 | } |
105 | 104 |
|
106 | 105 | &:global(.small) { |
107 | | - height: 2rem; |
108 | | - padding: 0 var(--spacing-12); |
| 106 | + block-size: 2rem; |
| 107 | + padding-inline: var(--spacing-12); |
109 | 108 | border-radius: var(--border-radius-12); |
110 | 109 | font-size: var(--font-size-12); |
111 | 110 | } |
112 | 111 |
|
113 | | - &:global(.iconOnly), |
114 | | - &:global(.iconSmall) { |
115 | | - padding: 0; |
116 | | - } |
117 | | -
|
118 | | - &:global(.iconOnly) { |
119 | | - width: 2.5rem; |
120 | | - } |
121 | | -
|
122 | | - &:global(.iconSmall) { |
123 | | - width: 2rem; |
124 | | - height: 2rem; |
125 | | - border-radius: var(--border-radius-12); |
126 | | - } |
127 | | -
|
128 | 112 | &:global(.secondary) { |
129 | 113 | background: var(--color-surface-base); |
130 | 114 | color: var(--color-text-primary); |
131 | 115 | border-color: var(--color-border-default); |
132 | 116 |
|
133 | | - &:focus-visible, |
134 | 117 | &:hover { |
135 | 118 | background: var(--color-surface-subtle); |
136 | 119 | border-color: var(--color-border-default); |
137 | 120 | color: var(--color-text-primary); |
138 | 121 | } |
139 | 122 |
|
140 | | - &:active { |
141 | | - transform: translateY(1px); |
142 | | - } |
143 | | - } |
144 | | -
|
145 | | - &:global(.ghost) { |
146 | | - background: transparent; |
147 | | - color: var(--color-text-secondary); |
148 | | -
|
149 | | - &:focus-visible, |
150 | | - &:hover { |
| 123 | + &:focus-visible { |
151 | 124 | background: var(--color-surface-subtle); |
| 125 | + border-color: var(--color-border-default); |
152 | 126 | color: var(--color-text-primary); |
153 | 127 | } |
154 | 128 |
|
|
162 | 136 | color: var(--color-danger); |
163 | 137 | border-color: color-mix(in oklch, var(--color-danger), transparent 76%); |
164 | 138 |
|
165 | | - &:focus-visible, |
166 | 139 | &:hover { |
167 | 140 | background: color-mix(in oklch, var(--color-danger), transparent 90%); |
168 | 141 | } |
169 | 142 |
|
| 143 | + &:focus-visible { |
| 144 | + background: color-mix(in oklch, var(--color-danger), transparent 90%); |
| 145 | + outline-color: color-mix(in oklch, var(--color-danger), transparent 48%); |
| 146 | + } |
| 147 | +
|
170 | 148 | &:active { |
171 | 149 | transform: translateY(1px); |
172 | 150 | } |
173 | 151 | } |
174 | 152 | } |
175 | 153 |
|
176 | | - .button:disabled, |
177 | | - .button:disabled:focus-visible, |
178 | | - .button:disabled:hover, |
179 | | - .button:disabled:active { |
| 154 | + .component:disabled, |
| 155 | + .component:disabled:focus-visible, |
| 156 | + .component:disabled:hover, |
| 157 | + .component:disabled:active { |
180 | 158 | cursor: not-allowed; |
181 | 159 | transform: none; |
182 | 160 | color: var(--color-text-muted); |
183 | 161 | background: var(--color-surface-subtle); |
184 | 162 | border-color: transparent; |
| 163 | + outline-color: transparent; |
185 | 164 | } |
186 | 165 |
|
187 | 166 | .icon { |
188 | 167 | font-size: 1.05em; |
189 | 168 | flex-shrink: 0; |
190 | 169 | } |
| 170 | +
|
| 171 | + @media (prefers-reduced-motion: reduce) { |
| 172 | + .component:active { |
| 173 | + transform: none; |
| 174 | + } |
| 175 | + } |
191 | 176 | </style> |
0 commit comments