diff --git a/src/material/sort/BUILD.bazel b/src/material/sort/BUILD.bazel index 733c0754d389..4c8322720cf1 100644 --- a/src/material/sort/BUILD.bazel +++ b/src/material/sort/BUILD.bazel @@ -19,6 +19,7 @@ ng_module( assets = [":sort-header.css"] + glob(["**/*.html"]), module_name = "@angular/material/sort", deps = [ + "//src/cdk/a11y", "//src/cdk/coercion", "//src/material/core", "@npm//@angular/animations", diff --git a/src/material/sort/sort-header.html b/src/material/sort/sort-header.html index 99457b14c087..96bc176f8fb8 100644 --- a/src/material/sort/sort-header.html +++ b/src/material/sort/sort-header.html @@ -3,9 +3,7 @@ [class.mat-sort-header-position-before]="arrowPosition == 'before'"> diff --git a/src/material/sort/sort-header.scss b/src/material/sort/sort-header.scss index 20e630322a9a..70ad3f7a36ee 100644 --- a/src/material/sort/sort-header.scss +++ b/src/material/sort/sort-header.scss @@ -32,6 +32,13 @@ $mat-sort-header-arrow-hint-opacity: 0.38; font: inherit; color: currentColor; + // Usually we could rely on the arrow showing up to be focus indication, but if a header is + // active, the arrow will always be shown so the user has no way of telling the difference. + [mat-sort-header].cdk-keyboard-focused &, + [mat-sort-header].cdk-program-focused & { + border-bottom: solid 1px currentColor; + } + // The `outline: 0` from above works on all browsers, however Firefox also // adds a special `focus-inner` which we have to disable explicitly. See: // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#Firefox diff --git a/src/material/sort/sort-header.ts b/src/material/sort/sort-header.ts index d0ac8db4cafa..72b2357be57a 100644 --- a/src/material/sort/sort-header.ts +++ b/src/material/sort/sort-header.ts @@ -17,8 +17,10 @@ import { Optional, ViewEncapsulation, Inject, + ElementRef, } from '@angular/core'; import {CanDisable, CanDisableCtor, mixinDisabled} from '@angular/material/core'; +import {FocusMonitor} from '@angular/cdk/a11y'; import {merge, Subscription} from 'rxjs'; import {MatSort, MatSortable} from './sort'; import {matSortAnimations} from './sort-animations'; @@ -138,7 +140,13 @@ export class MatSortHeader extends _MatSortHeaderMixinBase changeDetectorRef: ChangeDetectorRef, @Optional() public _sort: MatSort, @Inject('MAT_SORT_HEADER_COLUMN_DEF') @Optional() - public _columnDef: MatSortHeaderColumnDef) { + public _columnDef: MatSortHeaderColumnDef, + /** + * @deprecated _focusMonitor and _elementRef to become required parameters. + * @breaking-change 10.0.0 + */ + private _focusMonitor?: FocusMonitor, + private _elementRef?: ElementRef) { // Note that we use a string token for the `_columnDef`, because the value is provided both by // `material/table` and `cdk/table` and we can't have the CDK depending on Material, // and we want to avoid having the sort header depending on the CDK table because @@ -163,6 +171,13 @@ export class MatSortHeader extends _MatSortHeaderMixinBase changeDetectorRef.markForCheck(); }); + + if (_focusMonitor && _elementRef) { + // We use the focus monitor because we also want to style + // things differently based on the focus origin. + _focusMonitor.monitor(_elementRef, true) + .subscribe(origin => this._setIndicatorHintVisible(!!origin)); + } } ngOnInit() { @@ -179,6 +194,11 @@ export class MatSortHeader extends _MatSortHeaderMixinBase } ngOnDestroy() { + // @breaking-change 10.0.0 Remove null check for _focusMonitor and _elementRef. + if (this._focusMonitor && this._elementRef) { + this._focusMonitor.stopMonitoring(this._elementRef); + } + this._sort.deregister(this); this._rerenderSubscription.unsubscribe(); } diff --git a/tools/public_api_guard/material/sort.d.ts b/tools/public_api_guard/material/sort.d.ts index 0a333793816d..24b5dfde271d 100644 --- a/tools/public_api_guard/material/sort.d.ts +++ b/tools/public_api_guard/material/sort.d.ts @@ -61,7 +61,8 @@ export declare class MatSortHeader extends _MatSortHeaderMixinBase implements Ca disableClear: boolean; id: string; start: 'asc' | 'desc'; - constructor(_intl: MatSortHeaderIntl, changeDetectorRef: ChangeDetectorRef, _sort: MatSort, _columnDef: MatSortHeaderColumnDef); + constructor(_intl: MatSortHeaderIntl, changeDetectorRef: ChangeDetectorRef, _sort: MatSort, _columnDef: MatSortHeaderColumnDef, + _focusMonitor?: FocusMonitor | undefined, _elementRef?: ElementRef | undefined); _getAriaSortAttribute(): "ascending" | "descending" | null; _getArrowDirectionState(): string; _getArrowViewState(): string;