Skip to content

Commit 02db4ba

Browse files
zelliottmmalerba
authored andcommitted
feat(material-experimental/*): Add focus indicators to all MDC except mdc-chips. (#18175)
1 parent 6886447 commit 02db4ba

File tree

21 files changed

+200
-41
lines changed

21 files changed

+200
-41
lines changed

src/dev-app/theme.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
@import '../material/core/theming/all-theme';
22
@import '../material/core/focus-indicator/focus-indicator';
3+
@import '../material-experimental/mdc-helpers/mdc-helpers';
34
@import '../material-experimental/mdc-slider/mdc-slider';
45
@import '../material-experimental/mdc-theming/all-theme';
56
@import '../material-experimental/mdc-typography/all-typography';
@@ -17,6 +18,7 @@
1718
// Include base styles for strong focus indicators.
1819
.demo-strong-focus {
1920
@include mat-strong-focus-indicators();
21+
@include mat-mdc-strong-focus-indicators();
2022
}
2123

2224
// Define the default theme (same as the example above).
@@ -39,6 +41,7 @@ $dark-theme: mat-dark-theme($dark-primary, $dark-accent, $dark-warn);
3941
// Include the default theme for focus indicators.
4042
.demo-strong-focus {
4143
@include mat-strong-focus-indicators-theme($candy-app-theme);
44+
@include mat-mdc-strong-focus-indicators-theme($candy-app-theme);
4245
}
4346

4447
// Include the alternative theme styles inside of a block with a CSS class. You can make this
@@ -55,4 +58,5 @@ $dark-theme: mat-dark-theme($dark-primary, $dark-accent, $dark-warn);
5558
// Include the dark theme for focus indicators.
5659
.demo-unicorn-dark-theme.demo-strong-focus {
5760
@include mat-strong-focus-indicators-theme($dark-theme);
61+
@include mat-mdc-strong-focus-indicators-theme($dark-theme);
5862
}

src/material-experimental/mdc-button/button-base.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export const MAT_BUTTON_HOST = {
3535
// an unthemed version. If color is undefined, apply a CSS class that makes it easy to
3636
// select and style this "theme".
3737
'[class.mat-unthemed]': '!color',
38+
'class': 'mat-mdc-focus-indicator',
3839
};
3940

4041
/** List of classes to add to buttons instances based on host attribute selector. */
@@ -147,6 +148,7 @@ export const MAT_ANCHOR_HOST = {
147148
// an unthemed version. If color is undefined, apply a CSS class that makes it easy to
148149
// select and style this "theme".
149150
'[class.mat-unthemed]': '!color',
151+
'class': 'mat-mdc-focus-indicator',
150152
};
151153

152154
/**

src/material-experimental/mdc-button/button.spec.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,15 @@ describe('MDC-based MatButton', () => {
257257
);
258258
});
259259
});
260+
261+
it('should have a focus indicator', () => {
262+
const fixture = TestBed.createComponent(TestApp);
263+
const buttonNativeElements =
264+
[...fixture.debugElement.nativeElement.querySelectorAll('a, button')];
265+
266+
expect(buttonNativeElements
267+
.every(element => element.classList.contains('mat-mdc-focus-indicator'))).toBe(true);
268+
});
260269
});
261270

262271
/** Test component that contains an MatButton. */

src/material-experimental/mdc-button/fab.scss

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,13 @@
99
.mat-mdc-fab, .mat-mdc-mini-fab {
1010
@include _mat-button-interactive();
1111
@include _mat-button-disabled();
12-
}
1312

14-
.mat-mdc-fab, .mat-mdc-mini-fab {
13+
// MDC adds some styles to fab and mini-fab that conflict with some of our focus indicator
14+
// styles and don't actually do anything. This undoes those conflicting styles.
15+
&:not(.mdc-ripple-upgraded):focus::before {
16+
background: transparent;
17+
opacity: 1;
18+
}
1519
}
1620

1721
// MDC expects the fab icon to contain this HTML content:

src/material-experimental/mdc-button/icon-button.scss

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,16 @@
1313
border-radius: 50%;
1414

1515
@include _mat-button-disabled();
16+
17+
// MDC adds some styles to icon buttons that conflict with some of our focus indicator styles
18+
// and don't actually do anything. This undoes those conflicting styles.
19+
&.mat-unthemed,
20+
&.mat-primary,
21+
&.mat-accent,
22+
&.mat-warn {
23+
&:not(.mdc-ripple-upgraded):focus::before {
24+
background: transparent;
25+
opacity: 1;
26+
}
27+
}
1628
}

src/material-experimental/mdc-checkbox/checkbox.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
</svg>
2828
<div class="mdc-checkbox__mixedmark"></div>
2929
</div>
30-
<div class="mat-mdc-checkbox-ripple" mat-ripple
30+
<div class="mat-mdc-checkbox-ripple mat-mdc-focus-indicator" mat-ripple
3131
[matRippleTrigger]="checkbox"
3232
[matRippleDisabled]="disableRipple || disabled"
3333
[matRippleCentered]="true"

src/material-experimental/mdc-checkbox/checkbox.spec.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,13 @@ describe('MDC-based MatCheckbox', () => {
588588
expect(inputElement.indeterminate).toBe(true, 'indeterminate should not change');
589589
}));
590590
});
591+
592+
it('should have a focus indicator', () => {
593+
const checkboxRippleNativeElement =
594+
checkboxNativeElement.querySelector('.mat-mdc-checkbox-ripple')!;
595+
596+
expect(checkboxRippleNativeElement.classList.contains('mat-mdc-focus-indicator')).toBe(true);
597+
});
591598
});
592599

593600
describe('with change event and no initial value', () => {

src/material-experimental/mdc-helpers/_mdc-helpers.scss

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
@import '@material/theme/functions.import';
77
@import '@material/theme/variables.import';
88
@import '@material/typography/variables.import';
9+
@import '../../material/core/style/layout-common';
910
@import '../../material/core/theming/theming';
1011
@import '../../material/core/typography/typography';
1112

@@ -211,3 +212,74 @@ $mat-typography-level-mappings: (
211212
// Reset the original values.
212213
$mdc-typography-styles: $orig-mdc-typography-styles !global;
213214
}
215+
216+
/// Mixin that turns on strong focus indicators.
217+
///
218+
/// @example
219+
/// .my-app {
220+
/// @include mat-mdc-strong-focus-indicators();
221+
/// }
222+
@mixin mat-mdc-strong-focus-indicators() {
223+
// Base styles for the focus indicators.
224+
.mat-mdc-focus-indicator::before {
225+
@include mat-fill();
226+
227+
border-radius: $mat-focus-indicator-border-radius;
228+
border: $mat-focus-indicator-border-width $mat-focus-indicator-border-style transparent;
229+
box-sizing: border-box;
230+
pointer-events: none;
231+
}
232+
233+
// By default, all focus indicators are flush with the bounding box of their
234+
// host element. For particular elements (listed below), default inset/offset
235+
// values are necessary to ensure that the focus indicator is sufficiently
236+
// contrastive and renders appropriately.
237+
238+
.mat-mdc-focus-indicator.mdc-button::before,
239+
.mat-mdc-focus-indicator.mdc-fab::before,
240+
.mat-mdc-focus-indicator.mdc-icon-button::before {
241+
margin: $mat-focus-indicator-border-width * -2;
242+
}
243+
244+
.mat-mdc-focus-indicator.mat-mdc-tab::before,
245+
.mat-mdc-focus-indicator.mat-mdc-tab-link::before {
246+
margin: $mat-focus-indicator-border-width * 2;
247+
}
248+
249+
// Render the focus indicator on focus. Defining a pseudo element's
250+
// content will cause it to render.
251+
252+
// For checkboxes and slide toggles, render the focus indicator when we know the hidden input
253+
// is focused (slightly different for each control).
254+
.mdc-checkbox__native-control:focus ~ .mat-mdc-focus-indicator::before,
255+
.mat-mdc-slide-toggle-focused .mat-mdc-focus-indicator::before,
256+
257+
// For all other components, render the focus indicator on focus.
258+
.mat-mdc-focus-indicator:focus::before {
259+
content: '';
260+
}
261+
}
262+
263+
/// Mixin that sets the color of the focus indicators.
264+
///
265+
/// @param {color|map} $themeOrMap
266+
/// If theme, focus indicators are set to the primary color of the theme. If
267+
/// color, focus indicators are set to that color.
268+
///
269+
/// @example
270+
/// .demo-dark-theme {
271+
/// @include mat-mdc-strong-focus-indicators-theme($darkThemeMap);
272+
/// }
273+
///
274+
/// @example
275+
/// .demo-red-theme {
276+
/// @include mat-mdc-strong-focus-indicators-theme(#F00);
277+
/// }
278+
@mixin mat-mdc-strong-focus-indicators-theme($themeOrColor) {
279+
.mat-mdc-focus-indicator::before {
280+
border-color: if(
281+
type-of($themeOrColor) == 'map',
282+
mat-color(map_get($themeOrColor, primary)),
283+
$themeOrColor);
284+
}
285+
}

src/material-experimental/mdc-menu/menu-item.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ import {MatMenuItem as BaseMatMenuItem} from '@angular/material/menu';
1818
inputs: ['disabled', 'disableRipple'],
1919
host: {
2020
'[attr.role]': 'role',
21-
// The MatMenuItem parent class adds `mat-menu-item` to the CSS classlist, but this should
22-
// not be added for this MDC equivalent menu item.
21+
// The MatMenuItem parent class adds `mat-menu-item` and `mat-focus-indicator` to the CSS
22+
// classlist, but these should not be added for this MDC equivalent menu item.
2323
'[class.mat-menu-item]': 'false',
24-
'class': 'mat-mdc-menu-item',
24+
'[class.mat-focus-indicator]': 'false',
25+
'class': 'mat-mdc-menu-item mat-mdc-focus-indicator',
2526
'[class.mat-mdc-menu-item-highlighted]': '_highlighted',
2627
'[class.mat-mdc-menu-item-submenu-trigger]': '_triggersSubmenu',
2728
'[attr.tabindex]': '_getTabIndex()',

src/material-experimental/mdc-menu/menu.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2160,6 +2160,18 @@ describe('MDC-based MatMenu', () => {
21602160

21612161
});
21622162

2163+
it('should have a focus indicator', () => {
2164+
const fixture = createComponent(SimpleMenu, [], [FakeIcon]);
2165+
fixture.detectChanges();
2166+
fixture.componentInstance.trigger.openMenu();
2167+
fixture.detectChanges();
2168+
const menuItemNativeElements =
2169+
Array.from(overlayContainerElement.querySelectorAll('.mat-mdc-menu-item'));
2170+
2171+
expect(menuItemNativeElements
2172+
.every(element => element.classList.contains('mat-mdc-focus-indicator'))).toBe(true);
2173+
});
2174+
21632175
});
21642176

21652177
describe('MatMenu default overrides', () => {

0 commit comments

Comments
 (0)