Skip to content

Commit

Permalink
feat(material/core): use strong focus indicators in high contrast mode
Browse files Browse the repository at this point in the history
Reuses the strong focus indicators styling for high-contrast mode users.
  • Loading branch information
jackierchu authored and crisbeto committed Jun 11, 2022
1 parent 503f12f commit 1256c6c
Show file tree
Hide file tree
Showing 41 changed files with 362 additions and 420 deletions.
14 changes: 6 additions & 8 deletions src/dev-app/theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,9 @@ $candy-app-theme: mat.define-light-theme((

.demo-strong-focus {
// Include base styles for strong focus indicators.
@include mat.strong-focus-indicators();
@include experimental.mdc-strong-focus-indicators();

// Include the default theme for focus indicators.
@include mat.strong-focus-indicators-theme($candy-app-theme);
@include experimental.mdc-strong-focus-indicators-theme($candy-app-theme);
$indicators-config: (border-color: mat.get-color-from-palette($candy-app-primary));
@include mat.strong-focus-indicators($indicators-config);
@include experimental.mdc-strong-focus-indicators($indicators-config);
}

// Include the alternative theme styles inside of a block with a CSS class. You can make this
Expand All @@ -60,8 +57,9 @@ $candy-app-theme: mat.define-light-theme((

// Include the dark theme colors for focus indicators.
&.demo-strong-focus {
@include mat.strong-focus-indicators-color($dark-colors);
@include experimental.mdc-strong-focus-indicators-color($dark-colors);
$indicators-config: (border-color: mat.get-color-from-palette($dark-primary));
@include mat.strong-focus-indicators($indicators-config);
@include experimental.mdc-strong-focus-indicators($indicators-config);
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/material-experimental/mdc-button/_button-base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@
.mat-mdc-focus-indicator {
@include mat.private-fill();
}

&:focus .mat-mdc-focus-indicator::before {
content: '';
}
}

// MDC's disabled buttons define a default cursor with pointer-events none. However, they select
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,3 @@
outline: solid 1px;
}
}

@include cdk.high-contrast(active, off) {
.mat-mdc-button-base:focus {
outline: solid 3px;
}
}
19 changes: 19 additions & 0 deletions src/material-experimental/mdc-button/button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,22 @@
right: $offset;
border-width: $offset;
}

// For the button element, default inset/offset values are necessary to ensure that
// the focus indicator is sufficiently contrastive and renders appropriately.
.mat-mdc-unelevated-button,
.mat-mdc-raised-button {
.mat-mdc-focus-indicator::before {
$default-border-width: mat.$focus-indicators-private-default-border-width;
$border-width: var(--mat-mdc-focus-indicator-border-width, #{$default-border-width});
$offset: calc(#{$border-width} + 2px);
margin: calc(#{$offset} * -1);
}
}

.mat-mdc-outlined-button .mat-mdc-focus-indicator::before {
$default-border-width: mat.$focus-indicators-private-default-border-width;
$border-width: var(--mat-mdc-focus-indicator-border-width, #{$default-border-width});
$offset: calc(#{$border-width} + 3px);
margin: calc(#{$offset} * -1);
}
7 changes: 7 additions & 0 deletions src/material-experimental/mdc-button/fab.scss
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@
.mat-icon, .material-icons {
@include mdc-fab.icon_();
}

.mat-mdc-focus-indicator::before {
$default-border-width: mat.$focus-indicators-private-default-border-width;
$border-width: var(--mat-mdc-focus-indicator-border-width, #{$default-border-width});
$offset: calc(#{$border-width} + 2px);
margin: calc(#{$offset} * -1);
}
}

.mat-mdc-extended-fab {
Expand Down
18 changes: 12 additions & 6 deletions src/material-experimental/mdc-checkbox/checkbox.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
@use '@angular/cdk';
@use '@angular/material' as mat;
@use '@material/checkbox/checkbox' as mdc-checkbox;
@use '@material/checkbox/checkbox-theme' as mdc-checkbox-theme;
Expand Down Expand Up @@ -49,11 +48,6 @@
.mdc-checkbox__native-control:not([disabled]):focus ~ .mdc-checkbox__ripple {
opacity: map.get(mdc-ripple.$dark-ink-opacities, hover) +
map.get(mdc-ripple.$dark-ink-opacities, focus);

@include cdk.high-contrast(active, off) {
outline: solid 3px;
opacity: 1;
}
}
}

Expand Down Expand Up @@ -125,3 +119,15 @@
$set-width: true,
$query: mdc-helpers.$mat-base-styles-query);
}

// Checkbox components have to set `border-radius: 50%` in order to support density scaling
// which will clip a square focus indicator so we have to turn it into a circle.
.mat-mdc-checkbox-ripple::before {
border-radius: 50%;
}

// For checkboxes render the focus indicator when we know
// the hidden input is focused (slightly different for each control).
.mdc-checkbox__native-control:focus ~ .mat-mdc-focus-indicator::before {
content: '';
}
45 changes: 31 additions & 14 deletions src/material-experimental/mdc-chips/chip.scss
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,6 @@
@include cdk.high-contrast(active, off) {
outline: solid 1px;

&.cdk-focused {
// Use 2px here since the dotted outline is a little thinner.
outline: dotted 2px;
}

.mdc-evolution-chip__checkmark-path {
// SVG colors won't be changed in high contrast mode and since the checkmark is white
// by default, it'll blend in with the background in black-on-white mode. Override the
Expand Down Expand Up @@ -180,25 +175,42 @@
left: 0;
pointer-events: none;
}
}

.mat-mdc-chip-remove {
.mat-icon {
width: inherit;
height: inherit;
font-size: inherit;
box-sizing: content-box;
// For the chip element, default inset/offset values are necessary to ensure that
// the focus indicator is sufficiently contrastive and renders appropriately.
.mat-mdc-focus-indicator::before {
$default-border-width: mat.$focus-indicators-private-default-border-width;
$border-width: var(--mat-mdc-focus-indicator-border-width, #{$default-border-width});
$offset: calc(#{$border-width} + 2px);
margin: calc(#{$offset} * -1);
}
}

// Fades out the trailing icon slightly so that it can become darker when focused.
// The MDC theming has variables for this, but the focus/hover states don't seem to work.
.mat-mdc-chip-remove {
// Fades out the trailing icon slightly so that it can become darker when focused.
// The MDC theming has variables for this, but the focus/hover states don't seem to work.
opacity: 0.54;

&:focus {
opacity: 1;
}

&::before {
$default-border-width: mat.$focus-indicators-private-default-border-width;
$offset: var(--mat-mdc-focus-indicator-border-width, #{$default-border-width});
margin: calc(#{$offset} * -1);

// MDC sets a padding a on the chip button which stretches out the focus indicator.
left: 8px;
right: 8px;
}

.mat-icon {
width: inherit;
height: inherit;
font-size: inherit;
box-sizing: content-box;
}
}

.mat-chip-edit-input {
Expand All @@ -215,3 +227,8 @@
outline-width: 3px;
}
}

// In the chips the individual actions have focus so we target a different element.
.mat-mdc-chip-action:focus .mat-mdc-focus-indicator::before {
content: '';
}
24 changes: 3 additions & 21 deletions src/material-experimental/mdc-core/option/option.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
@use '@angular/cdk';
@use '@angular/material' as mat;
@use '@material/list/evolution-mixins' as mdc-list-mixins;
@use '@material/list/evolution-variables' as mdc-list-variables;
Expand Down Expand Up @@ -91,24 +90,7 @@
}
}

.mat-mdc-option-active {
@include cdk.high-contrast(active, off) {
// A pseudo element is used here, because the active indication gets moved between options
// and we don't want the border from below to shift the layout around as it's added and removed.
&::before {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
pointer-events: none;

// We use a border here, rather than an outline, because the outline will be cut off
// by the `overflow: hidden` on the panel wrapping the options, whereas a border
// will push the element inwards. This could be done using `outline-offset: -1px`,
// however the property isn't supported on IE11.
border: solid 1px currentColor;
}
}
// For options, render the focus indicator when the class .mat-mdc-option-active is present.
.mat-mdc-option-active::before {
content: '';
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,28 @@
@use 'sass:map';
@use 'sass:meta';

@mixin _border-color($color) {
.mat-mdc-focus-indicator::before {
border-color: $color;
}
}

// stylelint-disable-next-line material/theme-mixin-api
@mixin color($config-or-theme-or-color) {
@if meta.type-of($config-or-theme-or-color) == 'color' {
@include _border-color($config-or-theme-or-color);
@include mat.focus-indicators-private-private-customize-focus-indicators((
border-color: $config-or-theme-or-color
), 'mat-mdc');
}
@else {
$config: mat.get-color-config($config-or-theme-or-color);
$border-color: mat.get-color-from-palette(map.get($config, primary));
@include _border-color($border-color);
@include mat.focus-indicators-private-private-customize-focus-indicators((
border-color: $border-color
), 'mat-mdc');
}
}

// stylelint-disable-next-line material/theme-mixin-api
@mixin theme($theme-or-color-config-or-color) {
@if meta.type-of($theme-or-color-config-or-color) == 'color' {
@include _border-color($theme-or-color-config-or-color);
@include mat.focus-indicators-private-private-customize-focus-indicators((
border-color: $theme-or-color-config-or-color
), 'mat-mdc');
}
@else {
$theme: mat.private-legacy-get-theme($theme-or-color-config-or-color);
Expand Down
97 changes: 4 additions & 93 deletions src/material-experimental/mdc-helpers/_focus-indicators.scss
Original file line number Diff line number Diff line change
@@ -1,104 +1,15 @@
@use '@angular/material' as mat;
@use 'sass:map';
@use '@angular/material' as mat;

/// Mixin that turns on strong focus indicators.
///
/// @example
/// .my-app {
/// @include mat-mdc-strong-focus-indicators($config);
/// }
@mixin strong-focus-indicators($config: ()) {
// Default focus indicator config.
$default-config: (
border-style: solid,
border-width: 3px,
border-radius: 4px,
border-color: black,
display: block,
);

// Merge default config with user config.
$config: map.merge($default-config, $config);
$border-style: map.get($config, border-style);
$border-width: map.get($config, border-width);
$border-radius: map.get($config, border-radius);

// Base styles for focus indicators.
.mat-mdc-focus-indicator::before {
@include mat.private-fill();
box-sizing: border-box;
pointer-events: none;
border: $border-width $border-style transparent;
border-radius: $border-radius;

.cdk-high-contrast-active & {
display: none;
}
}

// By default, all focus indicators are flush with the bounding box of their
// host element. For particular elements (listed below), default inset/offset
// values are necessary to ensure that the focus indicator is sufficiently
// contrastive and renders appropriately.

.mat-mdc-unelevated-button .mat-mdc-focus-indicator::before,
.mat-mdc-raised-button .mat-mdc-focus-indicator::before,
.mdc-fab .mat-mdc-focus-indicator::before,
.mat-mdc-chip-action-label .mat-mdc-focus-indicator::before {
margin: -($border-width + 2px);
}

.mat-mdc-outlined-button .mat-mdc-focus-indicator::before {
margin: -($border-width + 3px);
}

.mat-mdc-focus-indicator.mat-mdc-chip-remove::before {
margin: -$border-width;
}

// MDC sets a padding a on the button which stretches out the focus indicator.
.mat-mdc-focus-indicator.mat-mdc-chip-remove::before {
left: 8px;
right: 8px;
}

.mat-mdc-focus-indicator.mat-mdc-tab::before,
.mat-mdc-focus-indicator.mat-mdc-tab-link::before {
margin: 5px;
}

// These components have to set `border-radius: 50%` in order to support density scaling
// which will clip a square focus indicator so we have to turn it into a circle.
.mat-mdc-checkbox-ripple.mat-mdc-focus-indicator::before,
.mat-radio-ripple.mat-mdc-focus-indicator::before,
.mat-mdc-slider .mat-mdc-focus-indicator::before,
.mat-mdc-slide-toggle .mat-mdc-focus-indicator::before {
border-radius: 50%;
}

// Render the focus indicator on focus. Defining a pseudo element's
// content will cause it to render.

// For checkboxes, radios and slide toggles, render the focus indicator when we know
// the hidden input is focused (slightly different for each control).
.mdc-checkbox__native-control:focus ~ .mat-mdc-focus-indicator::before,
.mat-mdc-slide-toggle-focused .mat-mdc-focus-indicator::before,
.mat-mdc-radio-button.cdk-focused .mat-mdc-focus-indicator::before,

// In the chips the individual actions have focus so we target a different element.
.mat-mdc-chip-action:focus .mat-mdc-focus-indicator::before,

// For buttons and list items, render the focus indicator when the parent
// button or list item is focused.
.mat-mdc-button-base:focus .mat-mdc-focus-indicator::before,
.mat-mdc-list-item:focus > .mat-mdc-focus-indicator::before,

// For options, render the focus indicator when the class .mat-mdc-option-active is present.
.mat-mdc-focus-indicator.mat-mdc-option-active::before,

// In the MDC slider the focus indicator is inside the thumb.
.mdc-slider__thumb--focused .mat-mdc-focus-indicator::before,

// For all other components, render the focus indicator on focus.
.mat-mdc-focus-indicator:focus::before {
content: '';
}
@include mat.focus-indicators-private-private-customize-focus-indicators($config, 'mat-mdc');
}
14 changes: 11 additions & 3 deletions src/material-experimental/mdc-list/list.scss
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,17 @@
// The MDC-based list items already use the `::before` pseudo element for the standard
// focus/selected/hover state. Hence, we need to have a separate list-item spanning
// element that can be used for strong focus indicators.
.mat-mdc-list-item > .mat-mdc-focus-indicator {
@include mat.private-fill();
pointer-events: none;
.mat-mdc-list-item {
& > .mat-mdc-focus-indicator {
@include mat.private-fill();
pointer-events: none;
}

// For list items, render the focus indicator when the parent
// listem item is focused.
&:focus > .mat-mdc-focus-indicator::before {
content: '';
}
}

.mat-mdc-list-item.mdc-list-item--with-three-lines {
Expand Down
Loading

0 comments on commit 1256c6c

Please sign in to comment.