@angular-mdc/web
Version:
566 lines (562 loc) • 17 kB
JavaScript
/**
* @license
* Copyright (c) Dominic Carretto
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://github.com/trimox/angular-mdc-web/blob/master/LICENSE
*/
import { forwardRef, EventEmitter, Component, ViewEncapsulation, ChangeDetectionStrategy, NgZone, ChangeDetectorRef, ElementRef, Optional, Input, Output, ViewChild, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MdcFormFieldControl, MdcFormField, MdcFormFieldModule } from '@angular-mdc/web/form-field';
import { __awaiter } from 'tslib';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { supportsPassiveEventListeners, Platform } from '@angular/cdk/platform';
import { Subject, fromEvent } from 'rxjs';
import { takeUntil, filter } from 'rxjs/operators';
import { matches } from '@angular-mdc/web/dom';
import { MDCRippleFoundation } from '@material/ripple';
import { MDCCheckboxFoundation } from '@material/checkbox';
import { MDCComponent } from '@angular-mdc/web/base';
import { MdcRipple } from '@angular-mdc/web/ripple';
/**
* @fileoverview added by tsickle
* Generated from: checkbox/checkbox.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
let nextUniqueId = 0;
/**
* Change event object emitted by MdcCheckbox.
*/
class MdcCheckboxChange {
/**
* @param {?} source
* @param {?} checked
*/
constructor(source, checked) {
this.source = source;
this.checked = checked;
}
}
/** @type {?} */
const MDC_CHECKBOX_CONTROL_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef((/**
* @return {?}
*/
() => MdcCheckbox)),
multi: true
};
class MdcCheckbox extends MDCComponent {
/**
* @param {?} _platform
* @param {?} _ngZone
* @param {?} _changeDetectorRef
* @param {?} elementRef
* @param {?} ripple
* @param {?} _parentFormField
*/
constructor(_platform, _ngZone, _changeDetectorRef, elementRef, ripple, _parentFormField) {
super(elementRef);
this._platform = _platform;
this._ngZone = _ngZone;
this._changeDetectorRef = _changeDetectorRef;
this.elementRef = elementRef;
this.ripple = ripple;
this._parentFormField = _parentFormField;
/**
* Emits whenever the component is destroyed.
*/
this._destroy = new Subject();
this._initialized = false;
this._uniqueId = `mdc-checkbox-${++nextUniqueId}`;
this.id = this._uniqueId;
this.name = null;
this._checked = false;
this._touch = false;
this._disabled = false;
/**
* The value attribute of the native input element
*/
this.value = null;
this._indeterminate = false;
this._indeterminateToChecked = true;
this._disableRipple = false;
this.tabIndex = 0;
this.ariaLabel = '';
this.ariaLabelledby = null;
/**
* Fired when checkbox is checked or unchecked, but not when set
* indeterminate. Sends the state of [checked].
*/
this.change = new EventEmitter();
/**
* Fired when checkbox goes in and out of indeterminate state, but not when
* set to checked. Sends the state of [indeterminate];
*/
this.indeterminateChange = new EventEmitter();
/**
* View to model callback called when value changes
*/
this._onChange = (/**
* @return {?}
*/
() => { });
/**
* View to model callback called when component has been touched
*/
this._onTouched = (/**
* @return {?}
*/
() => { });
this._root = this.elementRef.nativeElement;
if (this._parentFormField) {
_parentFormField.elementRef.nativeElement.classList.add('mdc-form-field');
}
}
/**
* Returns the unique id for the visual hidden input.
* @return {?}
*/
get inputId() {
return `${this.id || this._uniqueId}-input`;
}
/**
* @return {?}
*/
get checked() {
return this._checked;
}
/**
* @param {?} value
* @return {?}
*/
set checked(value) {
if (value !== this.checked) {
this._checked = coerceBooleanProperty(value);
this._changeDetectorRef.markForCheck();
}
}
/**
* @return {?}
*/
get touch() {
return this._touch;
}
/**
* @param {?} value
* @return {?}
*/
set touch(value) {
this._touch = coerceBooleanProperty(value);
}
/**
* @return {?}
*/
get disabled() {
return this._disabled;
}
/**
* @param {?} value
* @return {?}
*/
set disabled(value) {
this.setDisabledState(value);
}
/**
* Alternative state of the checkbox, not user set-able state. Between
* [checked] and [indeterminate], only one can be true, though both can be
* false.
* `true` is INDETERMINATE and `false` is not.
* @return {?}
*/
get indeterminate() {
return this._indeterminate;
}
/**
* @param {?} value
* @return {?}
*/
set indeterminate(value) {
var _a;
if (this.disabled) {
return;
}
/** @type {?} */
const newValue = coerceBooleanProperty(value);
if (newValue !== this._indeterminate) {
this._indeterminate = newValue;
if (newValue) {
this.checked = false;
}
this.indeterminateChange.emit({ source: this, indeterminate: this._indeterminate });
this._changeDetectorRef.markForCheck();
(_a = this._foundation) === null || _a === void 0 ? void 0 : _a.handleChange();
}
}
/**
* Determines the state to go into when [indeterminate] state is toggled.
* `true` will go to checked and `false` will go to unchecked.
* @return {?}
*/
get indeterminateToChecked() {
return this._indeterminateToChecked;
}
/**
* @param {?} value
* @return {?}
*/
set indeterminateToChecked(value) {
this._indeterminateToChecked = coerceBooleanProperty(value);
this._changeDetectorRef.markForCheck();
}
/**
* Whether the ripple ink is disabled.
* @return {?}
*/
get disableRipple() {
return this._disableRipple;
}
/**
* @param {?} value
* @return {?}
*/
set disableRipple(value) {
this._disableRipple = coerceBooleanProperty(value);
}
/**
* @return {?}
*/
getDefaultFoundation() {
// Do not initialize foundation until ngAfterViewInit runs
if (!this._initialized) {
return undefined;
}
/** @type {?} */
const adapter = {
addClass: (/**
* @param {?} className
* @return {?}
*/
(className) => this._root.classList.add(className)),
removeClass: (/**
* @param {?} className
* @return {?}
*/
(className) => this._root.classList.remove(className)),
setNativeControlAttr: (/**
* @param {?} attr
* @param {?} value
* @return {?}
*/
(attr, value) => this._inputElement.nativeElement.setAttribute(attr, value)),
removeNativeControlAttr: (/**
* @param {?} attr
* @return {?}
*/
(attr) => this._inputElement.nativeElement.removeAttribute(attr)),
isIndeterminate: (/**
* @return {?}
*/
() => this.indeterminate),
isChecked: (/**
* @return {?}
*/
() => this.checked),
hasNativeControl: (/**
* @return {?}
*/
() => true),
setNativeControlDisabled: (/**
* @param {?} disabled
* @return {?}
*/
(disabled) => this._inputElement.nativeElement.disabled = disabled),
forceLayout: (/**
* @return {?}
*/
() => ((/** @type {?} */ (this._root))).offsetWidth),
isAttachedToDOM: (/**
* @return {?}
*/
() => true)
};
return new MDCCheckboxFoundation(adapter);
}
/**
* @return {?}
*/
_asyncBuildFoundation() {
return __awaiter(this, void 0, void 0, function* () {
this._foundation = this.getDefaultFoundation();
});
}
/**
* @return {?}
*/
ngAfterViewInit() {
this._initialized = true;
this._asyncBuildFoundation()
.then((/**
* @return {?}
*/
() => {
this._foundation.init();
this.setDisabledState(this._inputElement.nativeElement.disabled);
this.ripple = this._createRipple();
this.ripple.init();
}));
this._loadListeners();
}
/**
* @return {?}
*/
ngOnDestroy() {
this._destroy.next();
this._destroy.complete();
this.ripple.destroy();
this._foundation.destroy();
}
/**
* @param {?} value
* @return {?}
*/
writeValue(value) {
this.checked = !!value;
}
/**
* @param {?} fn
* @return {?}
*/
registerOnChange(fn) {
this._onChange = fn;
}
/**
* @param {?} fn
* @return {?}
*/
registerOnTouched(fn) {
this._onTouched = fn;
}
/**
* Focuses the checkbox.
* @return {?}
*/
focus() {
if (!this.disabled) {
this._inputElement.nativeElement.focus();
}
}
/**
* @param {?=} checked
* @return {?}
*/
toggle(checked) {
this._setState(checked);
}
/**
* @param {?} evt
* @return {?}
*/
_onInteraction(evt) {
// We have to stop propagation for click events on the visual hidden input element.
// Preventing bubbling for the second event will solve that issue.
evt.stopPropagation();
this._setState();
this._onChange(this.checked);
this._changeDetectorRef.markForCheck();
this.change.emit(new MdcCheckboxChange(this, this.checked));
}
/**
* @param {?} evt
* @return {?}
*/
_onInputClick(evt) {
evt.stopPropagation();
}
/**
* @param {?} disabled
* @return {?}
*/
setDisabledState(disabled) {
var _a;
/** @type {?} */
const newValue = coerceBooleanProperty(disabled);
if (newValue !== this._disabled) {
this._disabled = newValue;
(_a = this._foundation) === null || _a === void 0 ? void 0 : _a.setDisabled(newValue);
this._changeDetectorRef.markForCheck();
}
}
/**
* @private
* @param {?=} checked
* @return {?}
*/
_setState(checked) {
if (this.disabled) {
return;
}
if (this.indeterminate) {
this._checked = this.indeterminateToChecked;
this.indeterminate = false;
}
else {
this.checked = checked || !this.checked;
}
// Reset native input when clicked with noop. The native checkbox becomes checked after
// click, reset it to be align with `checked` value of `mdc-checkbox`.
this._inputElement.nativeElement.checked = this.checked;
this._ngZone.runOutsideAngular((/**
* @return {?}
*/
() => requestAnimationFrame((/**
* @return {?}
*/
() => this._foundation.handleChange()))));
}
/**
* @private
* @return {?}
*/
_createRipple() {
/** @type {?} */
const adapter = Object.assign(Object.assign({}, MdcRipple.createAdapter(this)), { isSurfaceActive: (/**
* @return {?}
*/
() => matches(this._inputElement.nativeElement, ':active')), isUnbounded: (/**
* @return {?}
*/
() => true), isSurfaceDisabled: (/**
* @return {?}
*/
() => this.disableRipple), deregisterInteractionHandler: (/**
* @param {?} evtType
* @param {?} handler
* @return {?}
*/
(evtType, handler) => this._inputElement.nativeElement.removeEventListener(evtType, handler, supportsPassiveEventListeners())), registerInteractionHandler: (/**
* @param {?} evtType
* @param {?} handler
* @return {?}
*/
(evtType, handler) => this._inputElement.nativeElement.addEventListener(evtType, handler, supportsPassiveEventListeners())) });
return new MdcRipple(this.elementRef, new MDCRippleFoundation(adapter));
}
/**
* @private
* @return {?}
*/
_loadListeners() {
if (!this._platform.isBrowser) {
return;
}
this._ngZone.runOutsideAngular((/**
* @return {?}
*/
() => fromEvent(this._root, 'animationend')
.pipe(takeUntil(this._destroy), filter((/**
* @param {?} e
* @return {?}
*/
(e) => e.target === this._root)))
.subscribe((/**
* @return {?}
*/
() => this._ngZone.run((/**
* @return {?}
*/
() => this._foundation.handleAnimationEnd()))))));
}
}
MdcCheckbox.decorators = [
{ type: Component, args: [{selector: 'mdc-checkbox',
exportAs: 'mdcCheckbox',
host: {
'[id]': 'id',
'class': 'mdc-checkbox',
'[class.mdc-checkbox--touch]': 'touch',
},
template: `
<input type="checkbox"
#input
class="mdc-checkbox__native-control"
[id]="inputId"
[attr.name]="name"
[tabIndex]="tabIndex"
[attr.aria-label]="ariaLabel || null"
[attr.aria-labelledby]="ariaLabelledby"
[disabled]="disabled"
[checked]="checked"
[attr.value]="value"
[indeterminate]="indeterminate"
(change)="_onInteraction($event)"
(click)="_onInputClick($event)"/>
<div class="mdc-checkbox__background">
<svg
class="mdc-checkbox__checkmark"
viewBox="0 0 24 24"
focusable="false">
<path class="mdc-checkbox__checkmark-path"
fill="none"
d="M1.73,12.91 8.1,19.28 22.79,4.59"/>
</svg>
<div class="mdc-checkbox__mixedmark"></div>
</div>
<div *ngIf="!disableRipple && !disabled" class="mdc-checkbox__ripple"></div>
`,
providers: [
MDC_CHECKBOX_CONTROL_VALUE_ACCESSOR,
MdcRipple,
{ provide: MdcFormFieldControl, useExisting: MdcCheckbox }
],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
},] },
];
/** @nocollapse */
MdcCheckbox.ctorParameters = () => [
{ type: Platform },
{ type: NgZone },
{ type: ChangeDetectorRef },
{ type: ElementRef },
{ type: MdcRipple },
{ type: MdcFormField, decorators: [{ type: Optional }] }
];
MdcCheckbox.propDecorators = {
id: [{ type: Input }],
name: [{ type: Input }],
checked: [{ type: Input }],
touch: [{ type: Input }],
disabled: [{ type: Input }],
value: [{ type: Input }],
indeterminate: [{ type: Input }],
indeterminateToChecked: [{ type: Input }],
disableRipple: [{ type: Input }],
tabIndex: [{ type: Input }],
ariaLabel: [{ type: Input, args: ['aria-label',] }],
ariaLabelledby: [{ type: Input, args: ['aria-labelledby',] }],
change: [{ type: Output }],
indeterminateChange: [{ type: Output }],
_inputElement: [{ type: ViewChild, args: ['input', { static: true },] }]
};
/**
* @fileoverview added by tsickle
* Generated from: checkbox/module.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class MdcCheckboxModule {
}
MdcCheckboxModule.decorators = [
{ type: NgModule, args: [{
imports: [CommonModule, MdcFormFieldModule],
exports: [
MdcFormFieldModule,
MdcCheckbox
],
declarations: [MdcCheckbox]
},] },
];
export { MDC_CHECKBOX_CONTROL_VALUE_ACCESSOR, MdcCheckbox, MdcCheckboxChange, MdcCheckboxModule };
//# sourceMappingURL=checkbox.js.map