UNPKG

@ribajs/bs5

Version:

Bootstrap 5 module for Riba.js

125 lines (109 loc) 3.24 kB
import { Component, TemplateFunction } from "@ribajs/core"; import { ThemeService } from "../../services/theme.js"; import { hasChildNodesTrim } from "@ribajs/utils"; import template from "./bs5-theme-button.component.html?raw"; import iconSunUrl from "@ribajs/iconset/svg/icon_sun.svg?url"; import iconMoonUrl from "@ribajs/iconset/svg/icon_moon.svg?url"; import { themeChoices } from "../../constants/index.js"; import type { Bs5ThemeButtonComponentScope, ThemeChoice, ThemeChangedData, JsxBs5ThemeButtonProps, } from "../../types/index.js"; /** * @see https://github.com/TypeStrong/typedoc/blob/master/src/lib/output/themes/default/assets/typedoc/Theme.ts */ export class Bs5ThemeButtonComponent extends Component { public static tagName = "bs5-theme-button"; protected theme: ThemeService; static get observedAttributes(): (keyof JsxBs5ThemeButtonProps)[] { return ["mode", "labels", "light-icon-src", "icon-size", "dark-icon-src"]; } public scope: Bs5ThemeButtonComponentScope = { // Options // Attributes mode: "dropdown", labels: { os: "OS", light: "Light", dark: "Dark", }, lightIconSrc: iconSunUrl, darkIconSrc: iconMoonUrl, iconSize: 32, // Methods / Properties setTheme: this.setTheme.bind(this), selectTheme: this.selectTheme.bind(this), toggleTheme: this.toggleTheme.bind(this), selected: undefined, choices: themeChoices, }; constructor() { super(); this.theme = ThemeService.getSingleton(); } protected connectedCallback() { super.connectedCallback(); this.init(Bs5ThemeButtonComponent.observedAttributes); this.addEventListeners(); this.initTheme(); } protected addEventListeners() { this.theme.onChange((data) => { this.onChange(data); }); } protected onChange(data: ThemeChangedData) { this.scope.selected = data.newValue.choice; } protected async beforeBind() { this.initTheme(); } initTheme() { const selectEl = this.getElementsByTagName("select")?.item(0); const data = this.theme.init(); this.scope.selected = data.choice || undefined; if (selectEl) this.theme.select(this.scope.selected, selectEl); } public setTheme(theme: ThemeChoice) { this.theme.set(theme); } /** * Used in `dropdown` mode (which uses a select element) */ public selectTheme() { if (this.scope.selected) this.theme.set(this.scope.selected); } /** * Used in `icon` mode (which uses a button element) */ public toggleTheme() { const current = this.theme.getScheme(); if (current.bySystem) { if (current.systemIsLight) { this.theme.set("dark"); } else { this.theme.set("light"); } } else if (current.isDark) { if (current.supported && current.systemIsLight) { this.theme.set("os"); } else { this.theme.set("light"); } } else { if (current.supported && current.systemIsDark) { this.theme.set("os"); } else { this.theme.set("dark"); } } } protected template(): ReturnType<TemplateFunction> { if (!hasChildNodesTrim(this)) { return template; } else { return null; } } }