UNPKG

@bcodes/ngx-theme-service

Version:

Configurable theme switching service for use with CSS variables

213 lines (208 loc) 6.29 kB
import { DOCUMENT } from '@angular/common'; import { InjectionToken, Injectable, Inject, ɵɵdefineInjectable, ɵɵinject } from '@angular/core'; import { Subject, BehaviorSubject, timer } from 'rxjs'; import { tap, switchMap, takeUntil } from 'rxjs/operators'; /** * @fileoverview added by tsickle * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * Apply a CSS class to the `<html>` element when switching themes * @record */ function ThemeTransitionConfig() { } if (false) { /** @type {?} */ ThemeTransitionConfig.prototype.className; /** * remove class after duration in milliseconds * @type {?} */ ThemeTransitionConfig.prototype.duration; } /** * @record */ function ThemeServiceConfig() { } if (false) { /** @type {?} */ ThemeServiceConfig.prototype.themes; /** * theme that should always be on the target element if using explicit default theme * @type {?|undefined} */ ThemeServiceConfig.prototype.defaultTheme; /** * optional transition configuration * @type {?|undefined} */ ThemeServiceConfig.prototype.transitionConfig; /** * themes applied to <html> by default. Supply CSS selector to change * @type {?|undefined} */ ThemeServiceConfig.prototype.targetElementSelector; } /** @type {?} */ const THEME_CONFIG = new InjectionToken('ThemeService: Config'); // https://angular.io/guide/angular-compiler-options#strictmetadataemit // @dynamic class ThemeService { /** * @param {?} config * @param {?} document */ constructor(config, document) { this.config = config; this.document = document; this.stopListening$ = new Subject(); this.selectedTheme = new BehaviorSubject(this.config.defaultTheme || ''); this.selectedTheme$ = this.selectedTheme.asObservable(); this.setupSubscription(); } /** * @param {?} className * @return {?} */ switchTheme(className) { this.selectedTheme.next(className); } /** * @private * @return {?} */ setupSubscription() { /** @type {?} */ const transitionConfig = this.config.transitionConfig; /** @type {?} */ const nonDefaultThemes = this.config.themes.filter((/** * @param {?} c * @return {?} */ c => c !== this.config.defaultTheme)); this.selectedTheme .pipe(tap((/** * @param {?} theme * @return {?} */ theme => { this.removeClasses(nonDefaultThemes); // Conditional literal entries: // https://2ality.com/2017/04/conditional-literal-entries.html /** @type {?} */ const toAdd = [ ...(theme ? [theme] : []), ...(transitionConfig ? [transitionConfig.className] : []), ]; this.addClasses(toAdd); })), transitionConfig ? switchMap((/** * @param {?} value * @return {?} */ value => { return timer(transitionConfig.duration).pipe(tap((/** * @param {?} x * @return {?} */ x => { this.removeClasses([ transitionConfig.className, ]); }))); })) : tap((/** * @param {?} x * @return {?} */ (x) => { })), takeUntil(this.stopListening$)) .subscribe(); } /** * @private * @param {?} arr * @return {?} */ removeClasses(arr) { this.targetElement.classList.remove(...arr); } /** * @private * @param {?} arr * @return {?} */ addClasses(arr) { this.targetElement.classList.add(...arr); } /** * @private * @return {?} */ get targetElement() { /** @type {?} */ let elem; if (this.config.targetElementSelector) { elem = this.document.querySelector(this.config.targetElementSelector); if (!elem) { console.warn(`${this.config.targetElementSelector} not found, defaulting to <html>`); } } if (!elem) { elem = this.document.documentElement; } return elem; } /** * @return {?} */ ngOnDestroy() { this.stopListening$.next(true); } } ThemeService.decorators = [ { type: Injectable, args: [{ providedIn: 'root', },] } ]; /** @nocollapse */ ThemeService.ctorParameters = () => [ { type: undefined, decorators: [{ type: Inject, args: [THEME_CONFIG,] }] }, { type: Document, decorators: [{ type: Inject, args: [DOCUMENT,] }] } ]; /** @nocollapse */ ThemeService.ngInjectableDef = ɵɵdefineInjectable({ factory: function ThemeService_Factory() { return new ThemeService(ɵɵinject(THEME_CONFIG), ɵɵinject(DOCUMENT)); }, token: ThemeService, providedIn: "root" }); if (false) { /** * @type {?} * @private */ ThemeService.prototype.stopListening$; /** * @type {?} * @private */ ThemeService.prototype.selectedTheme; /** @type {?} */ ThemeService.prototype.selectedTheme$; /** * @type {?} * @private */ ThemeService.prototype.config; /** * @type {?} * @private */ ThemeService.prototype.document; } /** * @fileoverview added by tsickle * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @fileoverview added by tsickle * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ export { THEME_CONFIG, ThemeService }; //# sourceMappingURL=bcodes-ngx-theme-service.js.map