UNPKG

@grinway/theme-manager

Version:

This package sets themes to web application (with css variables)

151 lines (131 loc) 4.41 kB
import { typeChecker } from "@grinway/type-checker" import * as changeCase from "change-case" /** * Usage: * const theme = 'dark' * let bgColorVar = null * const callback = wonThemeEl => bgColorVar = themeManager.getStyleProp(wonThemeEl, themeManager.themeBgColorCssVar) * themeManager.set({ theme, callback }) * // you saved bgColorVar use it outside :) */ class ThemeManager { constructor() { this.#refreshElements() } /** * PREFIX FOR html[data-<this.themePrefix>-theme] */ get themePrefix() { return 'app' } /** * CSS VARIABLE */ get themeBgColorCssVar() { return `--${this.themePrefix}-theme-bg-color` } /** * CSS VARIABLE */ get themeColorCssVar() { return `--${this.themePrefix}-theme-color` } /** * API * Pass "theme", "callback" if you know the theme name OR "bgColor", "color", "callback" if you know only colors * * Usage: * * const theme = 'dark' * let colorBgValue = null * * // callback is needed to get the theme "#??????" color value that won * const callback = wonThemeEl => colorBgValue = themeManager.getStyleProp(wonThemeEl, themeManager.themeBgColorCssVar) * themeManager.set({ theme, callback }) * * // Imagine you have outside places where you need to set theme colors * this.someObj.someBgSetter1(colorBgValue) * this.someObj.someBgSetter2(colorBgValue) * this.someObj.someBgSetter3(colorBgValue) * * @param string theme Has priority over bgColor, color * @param callback callback Use to get the won theme some color: themeManager.getStyleProp(wonThemeEl, themeManager.themeBgColorCssVar) for instance */ set({ theme, bgColor, color, callback }) { this.#refreshElements() if (typeChecker.isNotFunction(callback)) { callback = wonThemeEl => { } } let wonThemeEl = null // theme string always wins over others if (typeChecker.isString(theme)) { this.#setHtmlStyle({ theme }) wonThemeEl = this.htmlEl callback(wonThemeEl) return this } this.#setRootStyle({ bgColor, color }) wonThemeEl = this.rootEl callback(wonThemeEl) return this } /** * API * * Works well inside callback of this.set method */ getStyleProp(el, property) { if (typeChecker.isObject(el) && typeChecker.isString(property)) { return getComputedStyle(el)?.getPropertyValue(property) } return null } /** * API * * Sets style (css) property with value * @return bool Whether or not property was set with passed value */ setStyleProp(el, property, value) { if (typeChecker.isNotObject(el) || typeChecker.isNotString(property) || typeChecker.isNotString(value)) { return false } try { el.style.setProperty(property, value) } catch (e) { return false } return true } #setHtmlStyle({ theme }) { if (typeChecker.isString(theme)) { this.htmlEl.dataset[this.#getDatasetThemeKey()] = theme } return this } #setRootStyle({ bgColor, color }) { const bgColorWasSet = this.setStyleProp(this.rootEl, this.themeBgColorCssVar, bgColor) const colorWasSet = this.setStyleProp(this.rootEl, this.themeColorCssVar, color) if (true === bgColorWasSet || true === colorWasSet) { this.htmlEl.dataset[this.#getDatasetThemeKey()] = '' } return this } #getDatasetThemeKey() { const themePrefix = changeCase.camelCase(this.themePrefix) return `${themePrefix}Theme` } #refreshElements() { this.#refreshHtml() this.#refreshRoot() } #refreshHtml() { this.htmlEl = document.querySelector('html') } #refreshRoot() { this.rootEl = document.querySelector(':root') } } const themeManager = new ThemeManager export { ThemeManager, themeManager }