Skip to content

Commit

Permalink
Aligning switch semantics with aria role (#2193)
Browse files Browse the repository at this point in the history
* Removes FF's focus ring to match other browsers

* Aligning switch semantics with aria role
  • Loading branch information
Michail Yasonik authored Aug 14, 2019
1 parent 9a33fb4 commit 76e58de
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 154 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## [`master`](https://github.com/elastic/eui/tree/master)

No public interface changes since `13.3.0`.
- Fixed `EuiSwitch` semantics to align with aria roles ([#2193](https://github.com/elastic/eui/pull/2193))
- Removed Firefox's focus ring to match other browsers ([#2193](https://github.com/elastic/eui/pull/2193))

## [`13.3.0`](https://github.com/elastic/eui/tree/v13.3.0)

Expand Down
4 changes: 2 additions & 2 deletions src-docs/src/views/form_controls/switch.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ export default class extends Component {
};
}

onChange = e => {
onChange = () => {
this.setState({
checked: e.target.checked,
checked: !this.state.checked,
});
};

Expand Down
3 changes: 2 additions & 1 deletion src/components/form/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ $euiFormBorderDisabledColor: transparentize($euiColorFullShade, .92) !default;
$euiFormCustomControlDisabledIconColor: shadeOrTint($euiColorMediumShade, 38%, 48.5%) !default; // exact 508c foreground for $euiColorLightShade
$euiFormControlDisabledColor: $euiColorMediumShade !default;
$euiFormControlBoxShadow: 0 1px 1px -1px transparentize($euiShadowColor, .8), 0 3px 2px -2px transparentize($euiShadowColor, .8);
$euiFormInputGroupLabelBackground: shadeOrTint($euiFormBackgroundDisabledColor, 0, 3%);
$euiFormInputGroupLabelBackground: shadeOrTint($euiFormBackgroundDisabledColor, 0, 3%);
$euiSwitchOffColor: lightOrDarkTheme(transparentize($euiColorMediumShade, .8), transparentize($euiColorMediumShade, .3));
114 changes: 62 additions & 52 deletions src/components/form/switch/__snapshots__/switch.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4,78 +4,88 @@ exports[`EuiSwitch assigns automatically generated ID to label 1`] = `
<div
class="euiSwitch"
>
<input
class="euiSwitch__input"
<button
class="euiSwitch__button"
id="generated-id"
type="checkbox"
/>
<span
class="euiSwitch__body"
role="switch"
>
<span
class="euiSwitch__thumb"
/>
<span
class="euiSwitch__track"
class="euiSwitch__body"
>
<svg
class="euiIcon euiIcon--medium euiIcon-isLoading euiSwitch__icon"
focusable="false"
height="16"
viewBox="0 0 16 16"
width="16"
xmlns="http://www.w3.org/2000/svg"
/>
<svg
class="euiIcon euiIcon--medium euiIcon-isLoading euiSwitch__icon euiSwitch__icon--checked"
focusable="false"
height="16"
viewBox="0 0 16 16"
width="16"
xmlns="http://www.w3.org/2000/svg"
<span
class="euiSwitch__thumb"
/>
<span
class="euiSwitch__track"
>
<svg
class="euiIcon euiIcon--medium euiIcon-isLoading euiSwitch__icon"
focusable="false"
height="16"
viewBox="0 0 16 16"
width="16"
xmlns="http://www.w3.org/2000/svg"
/>
<svg
class="euiIcon euiIcon--medium euiIcon-isLoading euiSwitch__icon euiSwitch__icon--checked"
focusable="false"
height="16"
viewBox="0 0 16 16"
width="16"
xmlns="http://www.w3.org/2000/svg"
/>
</span>
</span>
</span>
</button>
<label
class="euiSwitch__label"
for="generated-id"
/>
</div>
`;

exports[`EuiSwitch is rendered 1`] = `
<div
class="euiSwitch testClass1 testClass2"
>
<input
<button
aria-label="aria-label"
class="euiSwitch__input"
class="euiSwitch__button"
data-test-subj="test subject string"
id="test"
type="checkbox"
/>
<span
class="euiSwitch__body"
role="switch"
>
<span
class="euiSwitch__thumb"
/>
<span
class="euiSwitch__track"
class="euiSwitch__body"
>
<svg
class="euiIcon euiIcon--medium euiIcon-isLoading euiSwitch__icon"
focusable="false"
height="16"
viewBox="0 0 16 16"
width="16"
xmlns="http://www.w3.org/2000/svg"
/>
<svg
class="euiIcon euiIcon--medium euiIcon-isLoading euiSwitch__icon euiSwitch__icon--checked"
focusable="false"
height="16"
viewBox="0 0 16 16"
width="16"
xmlns="http://www.w3.org/2000/svg"
<span
class="euiSwitch__thumb"
/>
<span
class="euiSwitch__track"
>
<svg
class="euiIcon euiIcon--medium euiIcon-isLoading euiSwitch__icon"
focusable="false"
height="16"
viewBox="0 0 16 16"
width="16"
xmlns="http://www.w3.org/2000/svg"
/>
<svg
class="euiIcon euiIcon--medium euiIcon-isLoading euiSwitch__icon euiSwitch__icon--checked"
focusable="false"
height="16"
viewBox="0 0 16 16"
width="16"
xmlns="http://www.w3.org/2000/svg"
/>
</span>
</span>
</span>
</button>
<label
class="euiSwitch__label"
for="test"
/>
</div>
`;
122 changes: 52 additions & 70 deletions src/components/form/switch/_switch.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,63 @@
min-height: $euiSwitchHeight;

.euiSwitch__label {
cursor: pointer;
padding-left: $euiSizeS;
line-height: $euiSwitchHeight;
font-size: $euiFontSizeS;
vertical-align: middle;
}

/**
* 1. The input is "hidden" but still focusable.
* 2. Make sure it's still hidden when [disabled].
*/
.euiSwitch__input,
.euiSwitch__input[disabled] /* 2 */ {
position: absolute;
opacity: 0; /* 1 */
width: 100%;
height: 100%;
cursor: pointer;
}

.euiSwitch__input:focus + .euiSwitch__body {
.euiSwitch__button {
line-height: 0; // ensures button takes height of switch inside

.euiSwitch__thumb {
&:focus .euiSwitch__thumb {
@include euiCustomControlFocused;
}

&:disabled {
&:hover,
~ .euiSwitch__label:hover {
cursor: not-allowed;
}

.euiSwitch__body {
background-color: $euiSwitchOffColor;
}

.euiSwitch__thumb {
@include euiCustomControlDisabled;
background-color: $euiSwitchOffColor;
}

.euiSwitch__icon {
fill: $euiFormCustomControlDisabledIconColor;
}

+ .euiSwitch__label {
color: $euiFormControlDisabledColor;
}
}

&[aria-checked='false'] {
.euiSwitch__body {
background-color: $euiSwitchOffColor;
}

// When input is not checked, we shift around the positioning of the thumb and the icon
.euiSwitch__thumb { // move the thumb left
left: 0;
}

.euiSwitch__icon { // move the icon right
right: -$euiSizeS;

&.euiSwitch__icon--checked {
right: auto;
left: -($euiSwitchWidth - ($euiSwitchThumbSize / 2));
}
}
}
}

.euiSwitch__body {
Expand Down Expand Up @@ -77,64 +110,13 @@
fill: $euiColorEmptyShade;
}

/**
* The thumb is slightly scaled when in use, unless it's disabled.
*/
&:hover {
.euiSwitch__input:not(:disabled) ~ .euiSwitch__body {
.euiSwitch__thumb {
transform: scale(1.05);
}
&:hover .euiSwitch__button {
&:not(:disabled) .euiSwitch__thumb {
transform: scale(1.05);
}
}

&:active {
.euiSwitch__thumb {
&:active .euiSwitch__thumb {
transform: scale(.95);
}
}

.euiSwitch__input:disabled:hover {
cursor: not-allowed;
}

.euiSwitch__input:disabled ~ .euiSwitch__body,
.euiSwitch__input:checked:disabled ~ .euiSwitch__body {
background-color: lightOrDarkTheme(transparentize($euiColorMediumShade, .8), transparentize($euiColorMediumShade, .3));

.euiSwitch__thumb {
@include euiCustomControlDisabled;
background-color: lightOrDarkTheme(transparentize($euiColorMediumShade, .8), transparentize($euiColorMediumShade, .3));
}

.euiSwitch__icon {
fill: $euiFormCustomControlDisabledIconColor;
}

+ label {
color: $euiFormControlDisabledColor;
}
}

.euiSwitch__input:not(:checked):not(:disabled) ~ .euiSwitch__body {
background-color: lightOrDarkTheme(transparentize($euiColorMediumShade, .8), transparentize($euiColorMediumShade, .3));
}

/**
* When input is not checked, we shift around the positioning of sibling/child selectors.
*/
.euiSwitch__input:not(:checked) ~ .euiSwitch__body {
.euiSwitch__thumb {
left: 0;
}

.euiSwitch__icon {
right: -$euiSizeS;

&.euiSwitch__icon--checked {
right: auto;
left: -($euiSwitchWidth - ($euiSwitchThumbSize / 2));
}
}
}
}
12 changes: 9 additions & 3 deletions src/components/form/switch/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { CommonProps } from '../../common';

import { FunctionComponent, InputHTMLAttributes, ReactNode } from 'react';
import { FunctionComponent, ButtonHTMLAttributes, ReactNode } from 'react';

declare module '@elastic/eui' {
/**
* @see './switch.js'
*/
export type EuiSwitchProps = CommonProps &
InputHTMLAttributes<HTMLInputElement> & {
label?: ReactNode;
ButtonHTMLAttributes<HTMLButtonElement> & {
label: ReactNode;
checked: boolean;
onChange: (
event: React.FormEvent<HTMLButtonElement & { checked: boolean }>
) => void;
disabled?: boolean;
compressed?: boolean;
};

export const EuiSwitch: FunctionComponent<EuiSwitchProps>;
Expand Down
Loading

0 comments on commit 76e58de

Please sign in to comment.