A11Y: Improvements to `<DToggleSwitch/>` component (#23514)
This commit is contained in:
parent
c2cad3f269
commit
4238c57a1d
|
@ -0,0 +1,42 @@
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import I18n from "I18n";
|
||||||
|
import icon from "discourse-common/helpers/d-icon";
|
||||||
|
|
||||||
|
export default class DToggleSwitch extends Component {
|
||||||
|
<template>
|
||||||
|
<div class="d-toggle-switch">
|
||||||
|
<label class="d-toggle-switch--label">
|
||||||
|
{{! template-lint-disable no-redundant-role }}
|
||||||
|
<button
|
||||||
|
class="d-toggle-switch__checkbox"
|
||||||
|
type="button"
|
||||||
|
role="switch"
|
||||||
|
aria-checked={{this.checked}}
|
||||||
|
...attributes
|
||||||
|
></button>
|
||||||
|
{{! template-lint-enable no-redundant-role }}
|
||||||
|
|
||||||
|
<span class="d-toggle-switch__checkbox-slider">
|
||||||
|
{{#if @state}}
|
||||||
|
{{icon "check"}}
|
||||||
|
{{/if}}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<span class="d-toggle-switch__checkbox-label">
|
||||||
|
{{this.computedLabel}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
get computedLabel() {
|
||||||
|
if (this.args.label) {
|
||||||
|
return I18n.t(this.args.label);
|
||||||
|
}
|
||||||
|
return this.args.translatedLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
get checked() {
|
||||||
|
return this.args.state ? "true" : "false";
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,23 +0,0 @@
|
||||||
<div class="d-toggle-switch">
|
|
||||||
<label class="d-toggle-switch--label">
|
|
||||||
{{! template-lint-disable no-redundant-role }}
|
|
||||||
<button
|
|
||||||
class="d-toggle-switch__checkbox"
|
|
||||||
type="button"
|
|
||||||
role="switch"
|
|
||||||
aria-checked={{this.checked}}
|
|
||||||
...attributes
|
|
||||||
></button>
|
|
||||||
{{! template-lint-enable no-redundant-role }}
|
|
||||||
|
|
||||||
<span class="d-toggle-switch__checkbox-slider">
|
|
||||||
{{#if @state}}
|
|
||||||
{{d-icon "check"}}
|
|
||||||
{{/if}}
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<span class="d-toggle-switch__checkbox-label">
|
|
||||||
{{this.computedLabel}}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
|
@ -1,15 +0,0 @@
|
||||||
import Component from "@glimmer/component";
|
|
||||||
import I18n from "I18n";
|
|
||||||
|
|
||||||
export default class DToggleSwitch extends Component {
|
|
||||||
get computedLabel() {
|
|
||||||
if (this.args.label) {
|
|
||||||
return I18n.t(this.args.label);
|
|
||||||
}
|
|
||||||
return this.args.translatedLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
get checked() {
|
|
||||||
return this.args.state ? "true" : "false";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,6 +5,7 @@
|
||||||
&:focus {
|
&:focus {
|
||||||
.d-toggle-switch__checkbox-slider {
|
.d-toggle-switch__checkbox-slider {
|
||||||
outline: 2px solid var(--tertiary);
|
outline: 2px solid var(--tertiary);
|
||||||
|
outline-offset: 2px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +22,7 @@
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
|
||||||
&__label {
|
&__label {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -30,7 +32,23 @@
|
||||||
|
|
||||||
&__checkbox {
|
&__checkbox {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
visibility: hidden;
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
background: transparent;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
+ .d-toggle-switch__checkbox-slider {
|
||||||
|
outline: 2px solid var(--tertiary);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Outline should show only when tabbing, not clicking
|
||||||
|
&:not(:focus-visible) {
|
||||||
|
+ .d-toggle-switch__checkbox-slider {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__checkbox[aria-checked="true"] + .d-toggle-switch__checkbox-slider {
|
&__checkbox[aria-checked="true"] + .d-toggle-switch__checkbox-slider {
|
||||||
|
@ -57,7 +75,6 @@
|
||||||
border-radius: var(--toggle-switch-height);
|
border-radius: var(--toggle-switch-height);
|
||||||
width: var(--toggle-switch-width);
|
width: var(--toggle-switch-width);
|
||||||
height: var(--toggle-switch-height);
|
height: var(--toggle-switch-height);
|
||||||
margin-right: 0.5em;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
transition: background 0.25s;
|
transition: background 0.25s;
|
||||||
|
@ -87,5 +104,9 @@
|
||||||
top: calc(var(--toggle-switch-height) * 0.125);
|
top: calc(var(--toggle-switch-height) * 0.125);
|
||||||
left: calc(var(--toggle-switch-height) * 0.125);
|
left: calc(var(--toggle-switch-height) * 0.125);
|
||||||
transition: left 0.25s;
|
transition: left 0.25s;
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
transition-duration: 0ms;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue