Skip to content

Commit

Permalink
feat(material/chip): Add focus indicator (#18019)
Browse files Browse the repository at this point in the history
* Add focus indicators to mat-chip. Use a dynamically added element as the ripple target

* _document should be an optional param to avoid breaking change.

* Updated chips API golden.
  • Loading branch information
zelliott authored and mmalerba committed Feb 12, 2020
1 parent d3efac6 commit 78cfd3c
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 5 deletions.
23 changes: 20 additions & 3 deletions src/material/chips/chip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {DOCUMENT} from '@angular/common';
import {FocusableOption} from '@angular/cdk/a11y';
import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion';
import {BACKSPACE, DELETE, SPACE} from '@angular/cdk/keycodes';
Expand Down Expand Up @@ -105,7 +106,7 @@ export class MatChipTrailingIcon {}
inputs: ['color', 'disabled', 'disableRipple', 'tabIndex'],
exportAs: 'matChip',
host: {
'class': 'mat-chip',
'class': 'mat-chip mat-focus-indicator',
'[attr.tabindex]': 'disabled ? null : tabIndex',
'role': 'option',
'[class.mat-chip-selected]': 'selected',
Expand All @@ -128,6 +129,13 @@ export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDes
/** Reference to the RippleRenderer for the chip. */
private _chipRipple: RippleRenderer;

/**
* Reference to the element that acts as the chip's ripple target. This element is
* dynamically added as a child node of the chip. The chip itself cannot be used as the
* ripple target because it must be the host of the focus indicator.
*/
private _chipRippleTarget: HTMLElement;

/**
* Ripple configuration for ripples that are launched on pointer down. The ripple config
* is set to the global ripple options since we don't have any configurable options for
Expand Down Expand Up @@ -244,13 +252,22 @@ export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDes
@Optional() @Inject(ANIMATION_MODULE_TYPE) animationMode?: string,
// @breaking-change 9.0.0 `_changeDetectorRef` parameter to become required.
private _changeDetectorRef?: ChangeDetectorRef,
@Attribute('tabindex') tabIndex?: string) {
@Attribute('tabindex') tabIndex?: string,
// @breaking-change 11.0.0 `_document` parameter to become required.
@Optional() @Inject(DOCUMENT) _document?: any) {
super(_elementRef);

this._addHostClassName();

this._chipRipple = new RippleRenderer(this, _ngZone, _elementRef, platform);
// Dynamically create the ripple target, append it within the chip, and use it as the
// chip's ripple target. Adding the class '.mat-chip-ripple' ensures that it will have
// the proper styles.
this._chipRippleTarget = (_document || document).createElement('div');
this._chipRippleTarget.classList.add('mat-chip-ripple');
this._elementRef.nativeElement.appendChild(this._chipRippleTarget);
this._chipRipple = new RippleRenderer(this, _ngZone, this._chipRippleTarget, platform);
this._chipRipple.setupTriggerEvents(_elementRef);

this.rippleConfig = globalRippleOptions || {};
this._animationsDisabled = animationMode === 'NoopAnimations';
this.tabIndex = tabIndex != null ? (parseInt(tabIndex) || -1) : -1;
Expand Down
18 changes: 17 additions & 1 deletion src/material/chips/chips.scss
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ $mat-chip-remove-size: 18px;

.mat-chip {
position: relative;
overflow: hidden;
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;

Expand Down Expand Up @@ -171,6 +170,23 @@ $mat-chip-remove-size: 18px;
}
}

// Styles for the chip's dynamically added ripple target.
.mat-chip-ripple {
@include mat-fill;

// Disable pointer events for the ripple container and focus overlay because the container
// will overlay the user content and we don't want to disable mouse events on the user content.
// Pointer events can be safely disabled because the ripple trigger element is the host element.
pointer-events: none;

// Inherit the border radius from the parent so that ripples don't exceed the parent button
// boundaries.
border-radius: inherit;

// Ensures that the ripple effect doesn't overflow the ripple target.
overflow: hidden;
}

.mat-chip-list-wrapper {
display: flex;
flex-direction: row;
Expand Down
1 change: 1 addition & 0 deletions src/material/core/focus-indicator/_focus-indicator.scss
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
.mat-focus-indicator.mat-button-base::before,
.mat-focus-indicator.mat-button-base::before,
.mat-focus-indicator.mat-card::before,
.mat-focus-indicator.mat-chip::before,
.mat-focus-indicator.mat-sort-header-button::before {
margin: $border-width * -2;
}
Expand Down
2 changes: 1 addition & 1 deletion tools/public_api_guard/material/chips.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export declare class MatChip extends _MatChipMixinBase implements FocusableOptio
trailingIcon: MatChipTrailingIcon;
get value(): any;
set value(value: any);
constructor(_elementRef: ElementRef<HTMLElement>, _ngZone: NgZone, platform: Platform, globalRippleOptions: RippleGlobalOptions | null, animationMode?: string, _changeDetectorRef?: ChangeDetectorRef | undefined, tabIndex?: string);
constructor(_elementRef: ElementRef<HTMLElement>, _ngZone: NgZone, platform: Platform, globalRippleOptions: RippleGlobalOptions | null, animationMode?: string, _changeDetectorRef?: ChangeDetectorRef | undefined, tabIndex?: string, _document?: any);
_addHostClassName(): void;
_blur(): void;
_handleClick(event: Event): void;
Expand Down

0 comments on commit 78cfd3c

Please sign in to comment.