ipsos-components
Version:
Material Design components for Angular
325 lines (273 loc) • 8.37 kB
text/typescript
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {FocusableOption} from '@angular/cdk/a11y';
import {coerceBooleanProperty} from '@angular/cdk/coercion';
import {BACKSPACE, DELETE, SPACE} from '@angular/cdk/keycodes';
import {
Directive,
ElementRef,
EventEmitter,
Input,
OnDestroy,
Output,
} from '@angular/core';
import {CanColor, CanDisable, mixinColor, mixinDisabled} from '@angular/material/core';
import {Subject} from 'rxjs/Subject';
/** Represents an event fired on an individual `mat-chip`. */
export interface MatChipEvent {
/** The chip the event was fired on. */
chip: MatChip;
}
/** Event object emitted by MatChip when selected or deselected. */
export class MatChipSelectionChange {
constructor(
/** Reference to the chip that emitted the event. */
public source: MatChip,
/** Whether the chip that emitted the event is selected. */
public selected: boolean,
/** Whether the selection change was a result of a user interaction. */
public isUserInput = false) { }
}
// Boilerplate for applying mixins to MatChip.
/** @docs-private */
export class MatChipBase {
constructor(public _elementRef: ElementRef) {}
}
export const _MatChipMixinBase = mixinColor(mixinDisabled(MatChipBase), 'primary');
/**
* Dummy directive to add CSS class to basic chips.
* @docs-private
*/
export class MatBasicChip {
}
/**
* Material design styled Chip component. Used inside the MatChipList component.
*/
export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDestroy, CanColor,
CanDisable {
protected _value: any;
protected _selected: boolean = false;
protected _selectable: boolean = true;
protected _removable: boolean = true;
/** Whether the chip has focus. */
_hasFocus: boolean = false;
/** Whether the chip is selected. */
get selected(): boolean {
return this._selected;
}
set selected(value: boolean) {
this._selected = coerceBooleanProperty(value);
this.selectionChange.emit({
source: this,
isUserInput: false,
selected: value
});
}
/** The value of the chip. Defaults to the content inside <mat-chip> tags. */
get value(): any {
return this._value != undefined
? this._value
: this._elementRef.nativeElement.textContent;
}
set value(newValue: any) {
this._value = newValue;
}
/**
* Whether or not the chips are selectable. When a chip is not selectable,
* changes to it's selected state are always ignored.
*/
get selectable(): boolean {
return this._selectable;
}
set selectable(value: boolean) {
this._selectable = coerceBooleanProperty(value);
}
/**
* Determines whether or not the chip displays the remove styling and emits (remove) events.
*/
get removable(): boolean {
return this._removable;
}
set removable(value: boolean) {
this._removable = coerceBooleanProperty(value);
}
/** Emits when the chip is focused. */
_onFocus = new Subject<MatChipEvent>();
/** Emits when the chip is blured. */
_onBlur = new Subject<MatChipEvent>();
/** Emitted when the chip is selected or deselected. */
selectionChange = new EventEmitter<MatChipSelectionChange>();
/** Emitted when the chip is destroyed. */
destroyed = new EventEmitter<MatChipEvent>();
/**
* Emitted when the chip is destroyed.
* @deprecated Use 'destroyed' instead.
*/
destroy = this.destroyed;
/** Emitted when a chip is to be removed. */
removed = new EventEmitter<MatChipEvent>();
/**
* Emitted when a chip is to be removed.
* @deprecated Use `removed` instead.
*/
onRemove = this.removed;
get ariaSelected(): string | null {
return this.selectable ? this.selected.toString() : null;
}
constructor(public _elementRef: ElementRef) {
super(_elementRef);
}
ngOnDestroy(): void {
this.destroyed.emit({chip: this});
}
/** Selects the chip. */
select(): void {
this._selected = true;
this.selectionChange.emit({
source: this,
isUserInput: false,
selected: true
});
}
/** Deselects the chip. */
deselect(): void {
this._selected = false;
this.selectionChange.emit({
source: this,
isUserInput: false,
selected: false
});
}
/** Select this chip and emit selected event */
selectViaInteraction(): void {
this._selected = true;
// Emit select event when selected changes.
this.selectionChange.emit({
source: this,
isUserInput: true,
selected: true
});
}
/** Toggles the current selected state of this chip. */
toggleSelected(isUserInput: boolean = false): boolean {
this._selected = !this.selected;
this.selectionChange.emit({
source: this,
isUserInput,
selected: this._selected
});
return this.selected;
}
/** Allows for programmatic focusing of the chip. */
focus(): void {
this._elementRef.nativeElement.focus();
this._onFocus.next({chip: this});
}
/**
* Allows for programmatic removal of the chip. Called by the MatChipList when the DELETE or
* BACKSPACE keys are pressed.
*
* Informs any listeners of the removal request. Does not remove the chip from the DOM.
*/
remove(): void {
if (this.removable) {
this.removed.emit({chip: this});
}
}
/** Ensures events fire properly upon click. */
_handleClick(event: Event) {
// Check disabled
if (this.disabled) {
return;
}
event.preventDefault();
event.stopPropagation();
this.focus();
}
/** Handle custom key presses. */
_handleKeydown(event: KeyboardEvent): void {
if (this.disabled) {
return;
}
switch (event.keyCode) {
case DELETE:
case BACKSPACE:
// If we are removable, remove the focused chip
this.remove();
// Always prevent so page navigation does not occur
event.preventDefault();
break;
case SPACE:
// If we are selectable, toggle the focused chip
if (this.selectable) {
this.toggleSelected(true);
}
// Always prevent space from scrolling the page since the list has focus
event.preventDefault();
break;
}
}
_blur(): void {
this._hasFocus = false;
this._onBlur.next({chip: this});
}
}
/**
* Applies proper (click) support and adds styling for use with the Material Design "cancel" icon
* available at https://material.io/icons/#ic_cancel.
*
* Example:
*
* <mat-chip>
* <mat-icon matChipRemove>cancel</mat-icon>
* </mat-chip>
*
* You *may* use a custom icon, but you may need to override the `mat-chip-remove` positioning
* styles to properly center the icon within the chip.
*/
export class MatChipRemove {
constructor(protected _parentChip: MatChip) {
}
/** Calls the parent chip's public `remove()` method if applicable. */
_handleClick(): void {
if (this._parentChip.removable) {
this._parentChip.remove();
}
}
}