blob: 82bb269f6ceb3f5de8feb6a0ae04f2d7af7a462e [file] [log] [blame]
import { Directive, NgZone, ElementRef, Renderer2, Optional, Inject, Input, NgModule } from '@angular/core';
import { mixinDisabled, MatCommonModule } from '@angular/material/core';
import { AriaDescriber, A11yModule } from '@angular/cdk/a11y';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { ANIMATION_MODULE_TYPE } from '@angular/platform-browser/animations';
/**
* @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
*/
let nextId = 0;
// Boilerplate for applying mixins to MatBadge.
/** @docs-private */
class MatBadgeBase {
}
const _MatBadgeMixinBase = mixinDisabled(MatBadgeBase);
/** Directive to display a text badge. */
class MatBadge extends _MatBadgeMixinBase {
constructor(_ngZone, _elementRef, _ariaDescriber, _renderer, _animationMode) {
super();
this._ngZone = _ngZone;
this._elementRef = _elementRef;
this._ariaDescriber = _ariaDescriber;
this._renderer = _renderer;
this._animationMode = _animationMode;
/** Whether the badge has any content. */
this._hasContent = false;
this._color = 'primary';
this._overlap = true;
/**
* Position the badge should reside.
* Accepts any combination of 'above'|'below' and 'before'|'after'
*/
this.position = 'above after';
/** Size of the badge. Can be 'small', 'medium', or 'large'. */
this.size = 'medium';
/** Unique id for the badge */
this._id = nextId++;
if (typeof ngDevMode === 'undefined' || ngDevMode) {
const nativeElement = _elementRef.nativeElement;
if (nativeElement.nodeType !== nativeElement.ELEMENT_NODE) {
throw Error('matBadge must be attached to an element node.');
}
}
}
/** The color of the badge. Can be `primary`, `accent`, or `warn`. */
get color() { return this._color; }
set color(value) {
this._setColor(value);
this._color = value;
}
/** Whether the badge should overlap its contents or not */
get overlap() { return this._overlap; }
set overlap(val) {
this._overlap = coerceBooleanProperty(val);
}
/** Message used to describe the decorated element via aria-describedby */
get description() { return this._description; }
set description(newDescription) {
if (newDescription !== this._description) {
const badgeElement = this._badgeElement;
this._updateHostAriaDescription(newDescription, this._description);
this._description = newDescription;
if (badgeElement) {
newDescription ? badgeElement.setAttribute('aria-label', newDescription) :
badgeElement.removeAttribute('aria-label');
}
}
}
/** Whether the badge is hidden. */
get hidden() { return this._hidden; }
set hidden(val) {
this._hidden = coerceBooleanProperty(val);
}
/** Whether the badge is above the host or not */
isAbove() {
return this.position.indexOf('below') === -1;
}
/** Whether the badge is after the host or not */
isAfter() {
return this.position.indexOf('before') === -1;
}
ngOnChanges(changes) {
const contentChange = changes['content'];
if (contentChange) {
const value = contentChange.currentValue;
this._hasContent = value != null && `${value}`.trim().length > 0;
this._updateTextContent();
}
}
ngOnDestroy() {
const badgeElement = this._badgeElement;
if (badgeElement) {
if (this.description) {
this._ariaDescriber.removeDescription(badgeElement, this.description);
}
// When creating a badge through the Renderer, Angular will keep it in an index.
// We have to destroy it ourselves, otherwise it'll be retained in memory.
if (this._renderer.destroyNode) {
this._renderer.destroyNode(badgeElement);
}
}
}
/**
* Gets the element into which the badge's content is being rendered.
* Undefined if the element hasn't been created (e.g. if the badge doesn't have content).
*/
getBadgeElement() {
return this._badgeElement;
}
/** Injects a span element into the DOM with the content. */
_updateTextContent() {
if (!this._badgeElement) {
this._badgeElement = this._createBadgeElement();
}
else {
this._badgeElement.textContent = this._stringifyContent();
}
return this._badgeElement;
}
/** Creates the badge element */
_createBadgeElement() {
const badgeElement = this._renderer.createElement('span');
const activeClass = 'mat-badge-active';
const contentClass = 'mat-badge-content';
// Clear any existing badges which may have persisted from a server-side render.
this._clearExistingBadges(contentClass);
badgeElement.setAttribute('id', `mat-badge-content-${this._id}`);
badgeElement.classList.add(contentClass);
badgeElement.textContent = this._stringifyContent();
if (this._animationMode === 'NoopAnimations') {
badgeElement.classList.add('_mat-animation-noopable');
}
if (this.description) {
badgeElement.setAttribute('aria-label', this.description);
}
this._elementRef.nativeElement.appendChild(badgeElement);
// animate in after insertion
if (typeof requestAnimationFrame === 'function' && this._animationMode !== 'NoopAnimations') {
this._ngZone.runOutsideAngular(() => {
requestAnimationFrame(() => {
badgeElement.classList.add(activeClass);
});
});
}
else {
badgeElement.classList.add(activeClass);
}
return badgeElement;
}
/** Sets the aria-label property on the element */
_updateHostAriaDescription(newDescription, oldDescription) {
// ensure content available before setting label
const content = this._updateTextContent();
if (oldDescription) {
this._ariaDescriber.removeDescription(content, oldDescription);
}
if (newDescription) {
this._ariaDescriber.describe(content, newDescription);
}
}
/** Adds css theme class given the color to the component host */
_setColor(colorPalette) {
if (colorPalette !== this._color) {
const classList = this._elementRef.nativeElement.classList;
if (this._color) {
classList.remove(`mat-badge-${this._color}`);
}
if (colorPalette) {
classList.add(`mat-badge-${colorPalette}`);
}
}
}
/** Clears any existing badges that might be left over from server-side rendering. */
_clearExistingBadges(cssClass) {
const element = this._elementRef.nativeElement;
let childCount = element.children.length;
// Use a reverse while, because we'll be removing elements from the list as we're iterating.
while (childCount--) {
const currentChild = element.children[childCount];
if (currentChild.classList.contains(cssClass)) {
element.removeChild(currentChild);
}
}
}
/** Gets the string representation of the badge content. */
_stringifyContent() {
// Convert null and undefined to an empty string which is consistent
// with how Angular handles them in inside template interpolations.
const content = this.content;
return content == null ? '' : `${content}`;
}
}
MatBadge.decorators = [
{ type: Directive, args: [{
selector: '[matBadge]',
inputs: ['disabled: matBadgeDisabled'],
host: {
'class': 'mat-badge',
'[class.mat-badge-overlap]': 'overlap',
'[class.mat-badge-above]': 'isAbove()',
'[class.mat-badge-below]': '!isAbove()',
'[class.mat-badge-before]': '!isAfter()',
'[class.mat-badge-after]': 'isAfter()',
'[class.mat-badge-small]': 'size === "small"',
'[class.mat-badge-medium]': 'size === "medium"',
'[class.mat-badge-large]': 'size === "large"',
'[class.mat-badge-hidden]': 'hidden || !_hasContent',
'[class.mat-badge-disabled]': 'disabled',
},
},] }
];
MatBadge.ctorParameters = () => [
{ type: NgZone },
{ type: ElementRef },
{ type: AriaDescriber },
{ type: Renderer2 },
{ type: String, decorators: [{ type: Optional }, { type: Inject, args: [ANIMATION_MODULE_TYPE,] }] }
];
MatBadge.propDecorators = {
color: [{ type: Input, args: ['matBadgeColor',] }],
overlap: [{ type: Input, args: ['matBadgeOverlap',] }],
position: [{ type: Input, args: ['matBadgePosition',] }],
content: [{ type: Input, args: ['matBadge',] }],
description: [{ type: Input, args: ['matBadgeDescription',] }],
size: [{ type: Input, args: ['matBadgeSize',] }],
hidden: [{ type: Input, args: ['matBadgeHidden',] }]
};
/**
* @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
*/
class MatBadgeModule {
}
MatBadgeModule.decorators = [
{ type: NgModule, args: [{
imports: [
A11yModule,
MatCommonModule
],
exports: [MatBadge, MatCommonModule],
declarations: [MatBadge],
},] }
];
/**
* @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
*/
/**
* Generated bundle index. Do not edit.
*/
export { MatBadge, MatBadgeModule };
//# sourceMappingURL=badge.js.map