UNPKG

@angular-mdc/web

Version:
655 lines (647 loc) 22 kB
/** * @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 { InjectionToken, Component, ChangeDetectionStrategy, ViewEncapsulation, ChangeDetectorRef, ElementRef, Inject, ViewChild, NgZone, NgModule, Injectable, Injector, Optional, SkipSelf, ɵɵdefineInjectable, ɵɵinject, INJECTOR } from '@angular/core'; import { CommonModule } from '@angular/common'; import { OverlayModule, Overlay } from '@angular/cdk/overlay'; import { BasePortalOutlet, CdkPortalOutlet, PortalModule, PortalInjector, ComponentPortal } from '@angular/cdk/portal'; import { MdcButtonModule } from '@angular-mdc/web/button'; import { LiveAnnouncer } from '@angular/cdk/a11y'; import { MDCComponent } from '@angular-mdc/web/base'; import { Subject } from 'rxjs'; import { MDCSnackbarFoundation } from '@material/snackbar'; import { take } from 'rxjs/operators'; /** * @fileoverview added by tsickle * Generated from: snackbar/snackbar-ref.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * Reference to a snackbar dispatched from the snackbar service. * @template T */ class MdcSnackbarRef { /** * @param {?} containerInstance * @param {?} _overlayRef */ constructor(containerInstance, _overlayRef) { this.containerInstance = containerInstance; this._overlayRef = _overlayRef; /** * Subject for notifying the user that the snackbar has been dismissed. */ this._afterDismiss = new Subject(); this.componentInstance = containerInstance; } /** * Gets an observable that is notified when the snackbar is finished closing. * @return {?} */ afterDismiss() { return this._afterDismiss.asObservable(); } /** * @param {?=} reason * @return {?} */ dismiss(reason) { if (!this._afterDismiss.closed) { this._dismissedReason = reason; this._finishDismiss(); } } /** * Cleans up the DOM after closing. * @private * @return {?} */ _finishDismiss() { this._overlayRef.dispose(); this._afterDismiss.next(this._dismissedReason); this._afterDismiss.complete(); } } /** * @fileoverview added by tsickle * Generated from: snackbar/snackbar-config.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * Injection token that can be used to access the data that was passed in to a snackbar. * @type {?} */ const MDC_SNACKBAR_DATA = new InjectionToken('MdcSnackbarData'); /** * @template D */ class MdcSnackbarConfig { constructor() { /** * Data being injected into the child component. */ this.data = null; /** * Positions the action button/icon below the label instead of alongside it. */ this.stacked = false; /** * Positions the snackbar on the leading edge of the screen */ this.leading = false; /** * Positions the snackbar on the trailing edge of the screen */ this.trailing = false; /** * The layout direction of the snackbar content */ this.direction = 'ltr'; /** * Show dismiss ("X") icon */ this.dismiss = false; /** * Whether the snackbar closes when it is focused and the user presses the ESC key */ this.closeOnEscape = true; /** * The politeness level for the screen reader announcement. */ this.politeness = 'polite'; } } /** * @fileoverview added by tsickle * Generated from: snackbar/snackbar.component.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class MdcSnackbarComponent extends MDCComponent { /** * @param {?} _changeDetectorRef * @param {?} _liveAnnouncer * @param {?} elementRef * @param {?} snackbarRef * @param {?} data */ constructor(_changeDetectorRef, _liveAnnouncer, elementRef, snackbarRef, data) { super(elementRef); this._changeDetectorRef = _changeDetectorRef; this._liveAnnouncer = _liveAnnouncer; this.elementRef = elementRef; this.snackbarRef = snackbarRef; this.data = data; } /** * @return {?} */ get config() { return this.snackbarRef.componentInstance.snackbarConfig; } /** * @return {?} */ getDefaultFoundation() { /** @type {?} */ const adapter = { addClass: (/** * @param {?} className * @return {?} */ (className) => this._getHostElement().classList.add(className)), removeClass: (/** * @param {?} className * @return {?} */ (className) => this._getHostElement().classList.remove(className)), announce: (/** * @return {?} */ () => this.label.nativeElement ? this._liveAnnouncer.announce(this.config.data.message, this.config.politeness, this.config.timeoutMs || MDCSnackbarFoundation.numbers.ARIA_LIVE_DELAY_MS) : {}), notifyClosing: (/** * @return {?} */ () => { }), notifyOpened: (/** * @return {?} */ () => { }), notifyOpening: (/** * @return {?} */ () => { }), notifyClosed: (/** * @param {?} reason * @return {?} */ (reason) => this.snackbarRef.dismiss(reason)) }; return new MDCSnackbarFoundation(adapter); } /** * @return {?} */ ngOnInit() { this._changeDetectorRef.detectChanges(); this._applyClasses(); this._applyConfig(); } /** * @return {?} */ ngOnDestroy() { if (this._foundation) { this._foundation.destroy(); } } /** * @param {?} evt * @return {?} */ _onKeydown(evt) { this._foundation.handleKeyDown(evt); } /** * @param {?} evt * @return {?} */ _onActionClick(evt) { this._foundation.handleActionButtonClick(evt); } /** * @param {?} evt * @return {?} */ _onActionIconClick(evt) { this._foundation.handleActionIconClick(evt); } /** * @return {?} */ open() { this._foundation.open(); } /** * @param {?=} reason * @return {?} */ close(reason) { this._foundation.close(reason !== undefined ? reason.action ? 'action' : reason.dismiss ? 'dismiss' : '' : ''); } /** * @private * @return {?} */ _applyClasses() { /** @type {?} */ const classes = this.config.classes; if (classes) { if (classes instanceof Array) { this._getHostElement().classList.add(...(/** @type {?} */ (this.config.classes))); } else { this._getHostElement().classList.toggle(classes); } } /** @type {?} */ const actionClasses = this.config.actionClasses; if (actionClasses && this.action) { if (actionClasses instanceof Array) { this.action.nativeElement.classList.add(...(/** @type {?} */ (this.config.actionClasses))); } else { this.action.nativeElement.classList.toggle(actionClasses); } } if (this.dismiss) { /** @type {?} */ const dismissClasses = this.config.dismissClasses; if (dismissClasses) { if (dismissClasses instanceof Array) { this.dismiss.nativeElement.classList.add(...(/** @type {?} */ (this.config.dismissClasses))); } else { this.dismiss.nativeElement.classList.toggle(dismissClasses); } } } } /** * @private * @return {?} */ _applyConfig() { if (this.config.timeoutMs) { this._foundation.setTimeoutMs(this.config.timeoutMs); } if (this.config.dismiss) { this._foundation.setCloseOnEscape(this.config.closeOnEscape ? true : false); } } /** * Retrieves the DOM element of the component host. * @private * @return {?} */ _getHostElement() { return this.elementRef.nativeElement; } } MdcSnackbarComponent.decorators = [ { type: Component, args: [{selector: 'mdc-snackbar', host: { 'class': 'mdc-snackbar', '[dir]': 'this.config.direction', '[class.mdc-snackbar--stacked]': 'config.stacked', '[class.mdc-snackbar--leading]': 'config.leading', '[class.ngx-mdc-snackbar--trailing]': 'config.trailing', '(keydown)': '_onKeydown($event)' }, template: ` <div #surface class="mdc-snackbar__surface"> <div #label class="mdc-snackbar__label" role="status" aria-live="polite">{{data.message}}</div> <div class="mdc-snackbar__actions" *ngIf="data.action"> <button #action type="button" class="mdc-button mdc-snackbar__action" (click)="_onActionClick($event)">{{data.action}}</button> <button #dismiss *ngIf="config.dismiss" class="mdc-icon-button mdc-snackbar__dismiss material-icons" title="Dismiss" (click)="_onActionIconClick($event)">close</button> </div> </div>`, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, providers: [LiveAnnouncer] },] }, ]; /** @nocollapse */ MdcSnackbarComponent.ctorParameters = () => [ { type: ChangeDetectorRef }, { type: LiveAnnouncer }, { type: ElementRef }, { type: MdcSnackbarRef }, { type: undefined, decorators: [{ type: Inject, args: [MDC_SNACKBAR_DATA,] }] } ]; MdcSnackbarComponent.propDecorators = { label: [{ type: ViewChild, args: ['label', { static: true },] }], action: [{ type: ViewChild, args: ['action', { static: false },] }], dismiss: [{ type: ViewChild, args: ['dismiss', { static: false },] }] }; /** * @fileoverview added by tsickle * Generated from: snackbar/snackbar-container.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class MdcSnackbarContainer extends BasePortalOutlet { /** * @param {?} _ngZone * @param {?} snackbarConfig */ constructor(_ngZone, snackbarConfig) { super(); this._ngZone = _ngZone; this.snackbarConfig = snackbarConfig; /** * Subject for notifying that the snackbar has exited from view. */ this._onExit = new Subject(); } /** * Attach a component portal as content to this snackbar container. * @template T * @param {?} portal * @return {?} */ attachComponentPortal(portal) { return this._portalOutlet.attachComponentPortal(portal); } /** * Attach a template portal as content to this snackbar container. * @template C * @param {?} portal * @return {?} */ attachTemplatePortal(portal) { return this._portalOutlet.attachTemplatePortal(portal); } /** * @return {?} */ ngOnDestroy() { this._completeExit(); } /** * Waits for the zone to settle before removing the element. Helps prevent * errors where we end up removing an element which is in the middle of an animation. * @private * @return {?} */ _completeExit() { this._ngZone.onMicrotaskEmpty.asObservable().pipe(take(1)).subscribe((/** * @return {?} */ () => { this._onExit.next(); this._onExit.complete(); })); } } MdcSnackbarContainer.decorators = [ { type: Component, args: [{selector: 'mdc-snackbar-container', template: '<ng-template cdkPortalOutlet></ng-template>', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None },] }, ]; /** @nocollapse */ MdcSnackbarContainer.ctorParameters = () => [ { type: NgZone }, { type: MdcSnackbarConfig } ]; MdcSnackbarContainer.propDecorators = { _portalOutlet: [{ type: ViewChild, args: [CdkPortalOutlet, { static: true },] }] }; /** * @fileoverview added by tsickle * Generated from: snackbar/module.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class MdcSnackbarModule { } MdcSnackbarModule.decorators = [ { type: NgModule, args: [{ imports: [ CommonModule, OverlayModule, PortalModule, MdcButtonModule ], exports: [MdcSnackbarContainer], declarations: [MdcSnackbarContainer, MdcSnackbarComponent], entryComponents: [MdcSnackbarContainer, MdcSnackbarComponent] },] }, ]; /** * @fileoverview added by tsickle * Generated from: snackbar/snackbar.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * Injection token that can be used to specify default snackbar. * @type {?} */ const MDC_SNACKBAR_DEFAULT_OPTIONS = new InjectionToken('mdc-snackbar-default-options', { providedIn: 'root', factory: MDC_SNACKBAR_DEFAULT_OPTIONS_FACTORY, }); /** * \@docs-private * @return {?} */ function MDC_SNACKBAR_DEFAULT_OPTIONS_FACTORY() { return new MdcSnackbarConfig(); } class MdcSnackbar { /** * @param {?} _overlay * @param {?} _injector * @param {?} _parentSnackBar * @param {?} _defaultConfig */ constructor(_overlay, _injector, _parentSnackBar, _defaultConfig) { this._overlay = _overlay; this._injector = _injector; this._parentSnackBar = _parentSnackBar; this._defaultConfig = _defaultConfig; /** * Reference to the current snackbar in the view *at this level* (in the Angular injector tree). * If there is a parent snack-bar service, all operations should delegate to that parent * via `_openedSnackBarRef`. */ this._snackBarRefAtThisLevel = null; } /** * Reference to the currently opened snackbar at *any* level. * @return {?} */ get _openedSnackbarRef() { /** @type {?} */ const parent = this._parentSnackBar; return parent ? parent._openedSnackbarRef : this._snackBarRefAtThisLevel; } /** * @param {?} value * @return {?} */ set _openedSnackbarRef(value) { if (this._parentSnackBar) { this._parentSnackBar._openedSnackbarRef = value; } else { this._snackBarRefAtThisLevel = value; } } /** * Creates and dispatches a snackbar with a custom component for the content, removing any * currently opened snackbars. * * @template T * @param {?} component Component to be instantiated. * @param {?=} config Extra configuration for the snackbar. * @return {?} */ openFromComponent(component, config) { return (/** @type {?} */ (this._attach(component, config))); } /** * Opens a snackbar with a message and an optional action. * @param {?} message Message text. * @param {?=} action The label for the snackbar action. * @param {?=} config Additional configuration options for the snackbar. * @return {?} */ open(message, action = '', config) { /** @type {?} */ const _config = Object.assign(Object.assign({}, this._defaultConfig), config); // Since the user doesn't have access to the component, we can // override the data to pass in our own message and action. _config.data = { message, action }; return this.openFromComponent(MdcSnackbarComponent, _config); } /** * Dismisses the currently-visible snackbar. * @return {?} */ dismiss() { if (this._openedSnackbarRef) { if (this._openedSnackbarRef.instance instanceof MdcSnackbarComponent) { ((/** @type {?} */ (this._openedSnackbarRef.instance))).close(); } this._openedSnackbarRef.dismiss(); } } /** * @return {?} */ ngOnDestroy() { // Only dismiss the snackbar at the current level on destroy. if (this._snackBarRefAtThisLevel) { this._snackBarRefAtThisLevel.dismiss(); } } /** * Attaches the snackbar container component to the overlay. * @private * @param {?} overlayRef * @param {?} config * @return {?} */ _attachSnackbarContainer(overlayRef, config) { /** @type {?} */ const userInjector = config && config.viewContainerRef && config.viewContainerRef.injector; /** @type {?} */ const injector = new PortalInjector(userInjector || this._injector, new WeakMap([ [MdcSnackbarConfig, config] ])); /** @type {?} */ const containerPortal = new ComponentPortal(MdcSnackbarContainer, config.viewContainerRef, injector); /** @type {?} */ const containerRef = overlayRef.attach(containerPortal); containerRef.instance.snackbarConfig = config; return containerRef.instance; } /** * Places a new component or a template as the content of the snackbar container. * @private * @template T * @param {?} content * @param {?=} userConfig * @return {?} */ _attach(content, userConfig) { /** @type {?} */ const config = Object.assign(Object.assign(Object.assign({}, new MdcSnackbarConfig()), this._defaultConfig), userConfig); /** @type {?} */ const overlayRef = this._createOverlay(); /** @type {?} */ const container = this._attachSnackbarContainer(overlayRef, config); /** @type {?} */ const snackbarRef = new MdcSnackbarRef(container, overlayRef); /** @type {?} */ const injector = this._createInjector(config, snackbarRef); /** @type {?} */ const portal = new ComponentPortal(content, undefined, injector); /** @type {?} */ const contentRef = container.attachComponentPortal(portal); // We can't pass this via the injector, because the injector is created earlier. snackbarRef.instance = contentRef.instance; this._loadListeners(snackbarRef); this._openedSnackbarRef = snackbarRef; if (snackbarRef.instance instanceof MdcSnackbarComponent) { ((/** @type {?} */ (snackbarRef.instance))).open(); } return this._openedSnackbarRef; } /** * @private * @param {?} snackbarRef * @return {?} */ _loadListeners(snackbarRef) { // When the snackbar is dismissed, clear the reference to it. snackbarRef.afterDismiss().subscribe((/** * @return {?} */ () => { // Clear the snackbar ref if it hasn't already been replaced by a newer snackbar. if (this._openedSnackbarRef === snackbarRef) { this._openedSnackbarRef = null; } })); if (this._openedSnackbarRef) { this._openedSnackbarRef.dismiss(); } } /** * Creates a new overlay and places it in the correct location. * @private * @return {?} */ _createOverlay() { return this._overlay.create(); } /** * Creates an injector to be used inside of a snackbar component. * @private * @template T * @param {?} config Config that was used to create the snackbar. * @param {?} snackbarRef Reference to the snackbar. * @return {?} */ _createInjector(config, snackbarRef) { /** @type {?} */ const userInjector = config && config.viewContainerRef && config.viewContainerRef.injector; return new PortalInjector(userInjector || this._injector, new WeakMap([ [MdcSnackbarRef, snackbarRef], [MDC_SNACKBAR_DATA, config.data] ])); } } MdcSnackbar.decorators = [ { type: Injectable, args: [{ providedIn: MdcSnackbarModule },] }, ]; /** @nocollapse */ MdcSnackbar.ctorParameters = () => [ { type: Overlay }, { type: Injector }, { type: MdcSnackbar, decorators: [{ type: Optional }, { type: SkipSelf }] }, { type: MdcSnackbarConfig, decorators: [{ type: Inject, args: [MDC_SNACKBAR_DEFAULT_OPTIONS,] }] } ]; /** @nocollapse */ MdcSnackbar.ɵprov31 = ɵɵdefineInjectable({ factory: function MdcSnackbar_Factory() { return new MdcSnackbar(ɵɵinject(Overlay), ɵɵinject(INJECTOR), ɵɵinject(MdcSnackbar, 12), ɵɵinject(MDC_SNACKBAR_DEFAULT_OPTIONS)); }, token: MdcSnackbar, providedIn: MdcSnackbarModule }); export { MDC_SNACKBAR_DATA, MDC_SNACKBAR_DEFAULT_OPTIONS, MDC_SNACKBAR_DEFAULT_OPTIONS_FACTORY, MdcSnackbar, MdcSnackbarComponent, MdcSnackbarConfig, MdcSnackbarContainer, MdcSnackbarModule, MdcSnackbarRef }; //# sourceMappingURL=snackbar.js.map