angular-dark-mode
Version:
Add dark mode to your Angular applications with ease!
144 lines (134 loc) • 5.49 kB
JavaScript
import * as i0 from '@angular/core';
import { InjectionToken, Injectable, Optional, Inject } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { distinctUntilChanged } from 'rxjs/operators';
/**
* InjectionToken to override default options
*
* @example
*
* providers: [
* {
* provide: DARK_MODE_OPTIONS,
* useValue: {
* darkModeClass: 'my-dark-mode',
* lightModeClass: 'my-light-mode',
* },
* },
* ]
*/
const DARK_MODE_OPTIONS = new InjectionToken('DARK_MODE_OPTIONS');
/**
* Default options used in DarkModeService
*/
const defaultOptions = {
darkModeClass: 'dark-mode',
lightModeClass: 'light-mode',
preloadingClass: 'dark-mode-preloading',
storageKey: 'dark-mode',
element: document.body,
};
/* eslint-disable @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any */
function isNil(value) {
return value === null || value === undefined;
}
const prefersDarkSchemeQuery = '(prefers-color-scheme: dark)';
class MediaQueryService {
matchMedia(query) {
return window.matchMedia(query);
}
prefersDarkMode() {
return this.matchMedia(prefersDarkSchemeQuery).matches;
}
}
MediaQueryService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: MediaQueryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
MediaQueryService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: MediaQueryService, providedIn: 'root' });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: MediaQueryService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}] });
class DarkModeService {
constructor(rendererFactory, mediaQueryService,
// prettier-ignore
providedOptions) {
this.rendererFactory = rendererFactory;
this.mediaQueryService = mediaQueryService;
this.providedOptions = providedOptions;
this.options = { ...defaultOptions, ...(this.providedOptions || {}) };
this.renderer = this.rendererFactory.createRenderer(null, null);
this.darkModeSubject$ = new BehaviorSubject(this.getInitialDarkModeValue());
this.darkModeSubject$.getValue() ? this.enable() : this.disable();
this.removePreloadingClass();
}
/**
* An Observable representing current dark mode.
* Only fires the initial and distinct values.
*/
get darkMode$() {
return this.darkModeSubject$.asObservable().pipe(distinctUntilChanged());
}
toggle() {
this.darkModeSubject$.getValue() ? this.disable() : this.enable();
}
enable() {
const { element, darkModeClass, lightModeClass } = this.options;
this.renderer.removeClass(element, lightModeClass);
this.renderer.addClass(element, darkModeClass);
this.saveDarkModeToStorage(true);
this.darkModeSubject$.next(true);
}
disable() {
const { element, darkModeClass, lightModeClass } = this.options;
this.renderer.removeClass(element, darkModeClass);
this.renderer.addClass(element, lightModeClass);
this.saveDarkModeToStorage(false);
this.darkModeSubject$.next(false);
}
getInitialDarkModeValue() {
const darkModeFromStorage = this.getDarkModeFromStorage();
if (isNil(darkModeFromStorage)) {
return this.mediaQueryService.prefersDarkMode();
}
return darkModeFromStorage;
}
saveDarkModeToStorage(darkMode) {
localStorage.setItem(this.options.storageKey, JSON.stringify({ darkMode }));
}
getDarkModeFromStorage() {
const storageItem = localStorage.getItem(this.options.storageKey);
if (storageItem) {
try {
return JSON.parse(storageItem)?.darkMode;
}
catch (error) {
console.error('Invalid darkMode localStorage item:', storageItem, 'falling back to color scheme media query');
}
}
return null;
}
removePreloadingClass() {
// defer to next tick
setTimeout(() => {
this.renderer.removeClass(this.options.element, this.options.preloadingClass);
});
}
}
DarkModeService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: DarkModeService, deps: [{ token: i0.RendererFactory2 }, { token: MediaQueryService }, { token: DARK_MODE_OPTIONS, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
DarkModeService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: DarkModeService, providedIn: 'root' });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: DarkModeService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}], ctorParameters: function () { return [{ type: i0.RendererFactory2 }, { type: MediaQueryService }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [DARK_MODE_OPTIONS]
}] }]; } });
/*
* Public API Surface of angular-dark-mode
*/
/**
* Generated bundle index. Do not edit.
*/
export { DARK_MODE_OPTIONS, DarkModeService };
//# sourceMappingURL=angular-dark-mode.mjs.map