@angular-mdc/web
Version:
627 lines (623 loc) • 18.8 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, ChangeDetectionStrategy, ViewEncapsulation, NgZone, ChangeDetectorRef, ElementRef, Attribute, Input, Output, ViewChild, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { __awaiter } from 'tslib';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';
import { Platform, supportsPassiveEventListeners } from '@angular/cdk/platform';
import { Subject, fromEvent } from 'rxjs';
import { auditTime, takeUntil } from 'rxjs/operators';
import { MDCComponent } from '@angular-mdc/web/base';
import { MDCSliderFoundation } from '@material/slider';
/**
* @fileoverview added by tsickle
* Generated from: slider/slider.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
const MDC_SLIDER_CONTROL_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef((/**
* @return {?}
*/
() => MdcSlider)),
multi: true
};
class MdcSliderChange {
/**
* @param {?} source
* @param {?} value
*/
constructor(source, value) {
this.source = source;
this.value = value;
}
}
class MdcSlider extends MDCComponent {
/**
* @param {?} _platform
* @param {?} _ngZone
* @param {?} _changeDetectorRef
* @param {?} elementRef
* @param {?} tabIndex
*/
constructor(_platform, _ngZone, _changeDetectorRef, elementRef, tabIndex) {
super(elementRef);
this._platform = _platform;
this._ngZone = _ngZone;
this._changeDetectorRef = _changeDetectorRef;
this.elementRef = elementRef;
/**
* Emits whenever the component is destroyed.
*/
this._destroyed = new Subject();
this._initialized = false;
this.tabIndex = 0;
this._discrete = false;
this._markers = false;
this._min = 0;
this._max = 100;
this._step = 1;
this._value = null;
this._disabled = false;
this.change = new EventEmitter();
this.input = new EventEmitter();
/**
* Emits when the raw value of the slider changes. This is here primarily
* to facilitate the two-way binding for the `value` input.
*/
this.valueChange = new EventEmitter();
/**
* Function when touched
*/
this._onTouched = (/**
* @return {?}
*/
() => { });
/**
* Function when changed
*/
this._controlValueAccessorChangeFn = (/**
* @return {?}
*/
() => { });
this.tabIndex = parseInt(tabIndex, 10) || 0;
this._root = this.elementRef.nativeElement;
}
/**
* @return {?}
*/
get discrete() {
return this._discrete;
}
/**
* @param {?} value
* @return {?}
*/
set discrete(value) {
this._discrete = coerceBooleanProperty(value);
}
/**
* @return {?}
*/
get markers() {
return this._markers;
}
/**
* @param {?} value
* @return {?}
*/
set markers(value) {
this._markers = coerceBooleanProperty(value);
}
/**
* @return {?}
*/
get min() {
return this._min;
}
/**
* @param {?} value
* @return {?}
*/
set min(value) {
/** @type {?} */
const min = coerceNumberProperty(value);
if (min !== this._min) {
this._min = min;
}
}
/**
* @return {?}
*/
get max() {
return this._max;
}
/**
* @param {?} value
* @return {?}
*/
set max(value) {
/** @type {?} */
const max = coerceNumberProperty(value);
if (max !== this._max) {
this._max = max;
}
}
/**
* @return {?}
*/
get step() {
return this._step;
}
/**
* @param {?} value
* @return {?}
*/
set step(value) {
/** @type {?} */
const step = coerceNumberProperty(value, this._step);
if (step !== this._step) {
this._step = step;
}
}
/**
* @return {?}
*/
get value() {
if (this._value === null) {
this.value = this.min;
}
return this._value;
}
/**
* @param {?} newValue
* @return {?}
*/
set value(newValue) {
this._value = coerceNumberProperty(newValue, null);
}
/**
* @return {?}
*/
get disabled() {
return this._disabled;
}
/**
* @param {?} value
* @return {?}
*/
set disabled(value) {
this.setDisabledState(value);
}
/**
* @return {?}
*/
getDefaultFoundation() {
/** @type {?} */
const adapter = {
hasClass: (/**
* @param {?} className
* @return {?}
*/
(className) => this._root.classList.contains(className)),
addClass: (/**
* @param {?} className
* @return {?}
*/
(className) => this._root.classList.add(className)),
removeClass: (/**
* @param {?} className
* @return {?}
*/
(className) => this._root.classList.remove(className)),
getAttribute: (/**
* @param {?} name
* @return {?}
*/
(name) => this._root.getAttribute(name)),
setAttribute: (/**
* @param {?} name
* @param {?} value
* @return {?}
*/
(name, value) => this._root.setAttribute(name, value)),
removeAttribute: (/**
* @param {?} name
* @return {?}
*/
(name) => this._root.removeAttribute(name)),
computeBoundingRect: (/**
* @return {?}
*/
() => this._root.getBoundingClientRect()),
getTabIndex: (/**
* @return {?}
*/
() => ((/** @type {?} */ (this._root))).tabIndex),
registerInteractionHandler: (/**
* @template K
* @param {?} evtType
* @param {?} handler
* @return {?}
*/
(evtType, handler) => ((/** @type {?} */ (this._root))).addEventListener(evtType, handler)),
deregisterInteractionHandler: (/**
* @template K
* @param {?} evtType
* @param {?} handler
* @return {?}
*/
(evtType, handler) => ((/** @type {?} */ (this._root))).removeEventListener(evtType, handler)),
registerThumbContainerInteractionHandler: (/**
* @template K
* @param {?} evtType
* @param {?} handler
* @return {?}
*/
(evtType, handler) => {
this._ngZone.runOutsideAngular((/**
* @return {?}
*/
() => {
this.thumbContainer.nativeElement.addEventListener(evtType, handler, supportsPassiveEventListeners());
}));
}),
deregisterThumbContainerInteractionHandler: (/**
* @template K
* @param {?} evtType
* @param {?} handler
* @return {?}
*/
(evtType, handler) => this.thumbContainer.nativeElement.removeEventListener(evtType, handler, supportsPassiveEventListeners())),
registerBodyInteractionHandler: (/**
* @template K
* @param {?} evtType
* @param {?} handler
* @return {?}
*/
(evtType, handler) => document.body.addEventListener(evtType, handler)),
deregisterBodyInteractionHandler: (/**
* @template K
* @param {?} evtType
* @param {?} handler
* @return {?}
*/
(evtType, handler) => document.body.removeEventListener(evtType, handler)),
registerResizeHandler: (/**
* @return {?}
*/
() => { }),
deregisterResizeHandler: (/**
* @return {?}
*/
() => { }),
notifyInput: (/**
* @return {?}
*/
() => {
/** @type {?} */
const newValue = this._foundation.getValue();
if (newValue !== this.value) {
this.value = newValue;
this.input.emit(this._createChangeEvent(newValue));
}
}),
notifyChange: (/**
* @return {?}
*/
() => {
this.value = this._foundation.getValue();
this._emitChangeEvent((/** @type {?} */ (this.value)));
}),
setThumbContainerStyleProperty: (/**
* @param {?} propertyName
* @param {?} value
* @return {?}
*/
(propertyName, value) => this.thumbContainer.nativeElement.style.setProperty(propertyName, value)),
setTrackStyleProperty: (/**
* @param {?} propertyName
* @param {?} value
* @return {?}
*/
(propertyName, value) => this.track.nativeElement.style.setProperty(propertyName, value)),
setMarkerValue: (/**
* @param {?} value
* @return {?}
*/
(value) => {
this._changeDetectorRef.markForCheck();
(/** @type {?} */ (this.pinValueMarker)).nativeElement.innerText = value !== null ? value.toString() : null;
}),
setTrackMarkers: (/**
* @param {?} step
* @param {?} max
* @param {?} min
* @return {?}
*/
(step, max, min) => (/** @type {?} */ (this.trackMarkerContainer)).nativeElement.style.setProperty('background', this._getTrackMarkersBackground(step, min, max))),
isRTL: (/**
* @return {?}
*/
() => this._platform.isBrowser ?
window.getComputedStyle(this._root).getPropertyValue('direction') === 'rtl' : false),
};
return new MDCSliderFoundation(adapter);
}
/**
* @param {?} changes
* @return {?}
*/
ngOnChanges(changes) {
if (!this._initialized) {
return;
}
if (changes['step']) {
this._syncStepWithFoundation();
}
if (changes['max']) {
this._syncMaxWithFoundation();
}
if (changes['min']) {
this._syncMinWithFoundation();
}
if (changes['value']) {
this._syncValueWithFoundation();
}
if (changes['markers'] || changes['discrete']) {
this._refreshTrackMarkers();
}
}
/**
* @return {?}
*/
_asyncInitializeFoundation() {
return __awaiter(this, void 0, void 0, function* () {
this._foundation.init();
});
}
/**
* @return {?}
*/
ngAfterViewInit() {
if (this._platform.isBrowser) {
this._initialized = true;
this._asyncInitializeFoundation()
.then((/**
* @return {?}
*/
() => {
this._syncStepWithFoundation();
this._syncMaxWithFoundation();
this._syncMinWithFoundation();
this._syncValueWithFoundation();
this._foundation.setupTrackMarker();
this._loadListeners();
this._changeDetectorRef.markForCheck();
}));
}
}
/**
* @return {?}
*/
ngOnDestroy() {
this._destroyed.next();
this._destroyed.complete();
this.destroy();
}
/**
* @param {?} value
* @return {?}
*/
writeValue(value) {
this.value = value;
this._syncValueWithFoundation();
}
/**
* @param {?} fn
* @return {?}
*/
registerOnChange(fn) {
this._controlValueAccessorChangeFn = fn;
}
/**
* @param {?} fn
* @return {?}
*/
registerOnTouched(fn) {
this._onTouched = fn;
}
/**
* @param {?} disabled
* @return {?}
*/
setDisabledState(disabled) {
this._disabled = coerceBooleanProperty(disabled);
this._foundation.setDisabled(disabled);
this._changeDetectorRef.markForCheck();
}
/**
* @return {?}
*/
layout() {
this._foundation.layout();
}
/**
* @private
* @return {?}
*/
_loadListeners() {
this._ngZone.runOutsideAngular((/**
* @return {?}
*/
() => fromEvent(window, 'resize')
.pipe(auditTime(16), takeUntil(this._destroyed))
.subscribe((/**
* @return {?}
*/
() => this.layout()))));
}
/**
* @private
* @return {?}
*/
_syncValueWithFoundation() {
this._foundation.setValue((/** @type {?} */ (this.value)));
}
/**
* @private
* @return {?}
*/
_syncStepWithFoundation() {
this._foundation.setStep(this.step);
}
/**
* @private
* @return {?}
*/
_syncMinWithFoundation() {
this._foundation.setMin(this.min);
}
/**
* @private
* @return {?}
*/
_syncMaxWithFoundation() {
this._foundation.setMax(this.max);
}
/**
* @private
* @param {?} newValue
* @return {?}
*/
_createChangeEvent(newValue) {
return new MdcSliderChange(this, newValue);
}
/**
* @private
* @param {?} newValue
* @return {?}
*/
_emitChangeEvent(newValue) {
this._controlValueAccessorChangeFn(newValue);
this.valueChange.emit(newValue);
this.change.emit(this._createChangeEvent(newValue));
}
/**
* Keep calculation in css for better rounding/subpixel behavior.
* @private
* @param {?} step
* @param {?} min
* @param {?} max
* @return {?}
*/
_getTrackMarkersBackground(step, min, max) {
/** @type {?} */
const stepStr = step.toLocaleString();
/** @type {?} */
const maxStr = max.toLocaleString();
/** @type {?} */
const minStr = min.toLocaleString();
/** @type {?} */
const markerAmount = `((${maxStr} - ${minStr}) / ${stepStr})`;
/** @type {?} */
const markerWidth = `2px`;
/** @type {?} */
const markerBkgdImage = `linear-gradient(to right, currentColor ${markerWidth}, transparent 0)`;
/** @type {?} */
const markerBkgdLayout = `0 center / calc((100% - ${markerWidth}) / ${markerAmount}) 100% repeat-x`;
return `${markerBkgdImage} ${markerBkgdLayout}`;
}
/**
* Method that ensures that track markers are refreshed.
* @private
* @return {?}
*/
_refreshTrackMarkers() {
((/** @type {?} */ (this._foundation))).hasTrackMarker_ = this.markers;
this._foundation.setupTrackMarker();
}
}
MdcSlider.decorators = [
{ type: Component, args: [{selector: 'mdc-slider',
exportAs: 'mdcSlider',
host: {
'role': 'slider',
'aria-orientation': 'horizontal',
'[attr.tabindex]': 'tabIndex || 0',
'class': 'mdc-slider',
'[class.mdc-slider--discrete]': 'discrete',
'[class.mdc-slider--display-markers]': 'markers && discrete',
'(blur)': '_onTouched()',
},
template: `
<div class="mdc-slider__track-container">
<div #track class="mdc-slider__track"></div>
<div #markercontainer *ngIf="markers" class="mdc-slider__track-marker-container"></div>
</div>
<div #thumbcontainer class="mdc-slider__thumb-container">
<div *ngIf="discrete" class="mdc-slider__pin">
<span #pin class="mdc-slider__pin-value-marker"></span>
</div>
<svg #sliderThumb
class="mdc-slider__thumb"
width="21" height="21"
focusable="false">
<circle cx="10.5" cy="10.5" r="7.875"></circle>
</svg>
<div class="mdc-slider__focus-ring"></div>
</div>`,
providers: [MDC_SLIDER_CONTROL_VALUE_ACCESSOR],
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None
},] },
];
/** @nocollapse */
MdcSlider.ctorParameters = () => [
{ type: Platform },
{ type: NgZone },
{ type: ChangeDetectorRef },
{ type: ElementRef },
{ type: String, decorators: [{ type: Attribute, args: ['tabindex',] }] }
];
MdcSlider.propDecorators = {
tabIndex: [{ type: Input }],
discrete: [{ type: Input }],
markers: [{ type: Input }],
min: [{ type: Input }],
max: [{ type: Input }],
step: [{ type: Input }],
value: [{ type: Input }],
disabled: [{ type: Input }],
change: [{ type: Output }],
input: [{ type: Output }],
valueChange: [{ type: Output }],
thumbContainer: [{ type: ViewChild, args: ['thumbcontainer', { static: false },] }],
_sliderThumb: [{ type: ViewChild, args: ['sliderThumb', { static: false },] }],
track: [{ type: ViewChild, args: ['track', { static: false },] }],
pinValueMarker: [{ type: ViewChild, args: ['pin', { static: false },] }],
trackMarkerContainer: [{ type: ViewChild, args: ['markercontainer', { static: false },] }]
};
/**
* @fileoverview added by tsickle
* Generated from: slider/module.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class MdcSliderModule {
}
MdcSliderModule.decorators = [
{ type: NgModule, args: [{
imports: [CommonModule],
exports: [MdcSlider],
declarations: [MdcSlider]
},] },
];
export { MDC_SLIDER_CONTROL_VALUE_ACCESSOR, MdcSlider, MdcSliderChange, MdcSliderModule };
//# sourceMappingURL=slider.js.map