UNPKG

@universal-material/web

Version:
141 lines 6.14 kB
import { argbFromHex, CorePalette, TonalPalette } from '@material/material-color-utilities'; import { CssVarBuilder } from './css-var-builder.js'; import { neutralColors, neutralVariantColors } from './neutral-colors.js'; const getCss = (selector, content) => `${selector} { ${content}}`; export class ThemeBuilder { #corePalette; constructor(primaryColorHex) { this.colors = []; this.partial = false; this.cssClass = null; this.#corePalette = CorePalette.of(argbFromHex(primaryColorHex)); this.addColorFromPalette('primary', this.#corePalette.a1); } static create(primaryColorHex) { return new ThemeBuilder(primaryColorHex); } static createPartial(primaryColorHex) { const themeBuilder = new ThemeBuilder(primaryColorHex); themeBuilder.partial = true; return themeBuilder; } addColorFromHex(name, hex) { const palette = TonalPalette.fromInt(argbFromHex(hex)); this.addColorFromPalette(name, palette); return this; } addColorFromPalette(name, palette) { this.colors.push({ name, lightTone: 40, darkTone: 80, tonalPalette: palette }); this.colors.push({ name: `on-${name}`, lightTone: 100, darkTone: 20, tonalPalette: palette }); this.colors.push({ name: `${name}-container`, lightTone: 90, darkTone: 30, tonalPalette: palette }); this.colors.push({ name: `on-${name}-container`, lightTone: 10, darkTone: 90, tonalPalette: palette }); this.colors.push({ name: `${name}-fixed`, fixedTone: 90, tonalPalette: palette }); this.colors.push({ name: `${name}-fixed-dim`, fixedTone: 80, tonalPalette: palette }); this.colors.push({ name: `on-${name}-fixed`, fixedTone: 10, tonalPalette: palette }); this.colors.push({ name: `on-${name}-fixed-variant`, fixedTone: 30, tonalPalette: palette }); return this; } addStaticColor(name, hex, tone = 80) { const palette = TonalPalette.fromInt(argbFromHex(hex)); this.colors.push({ name, fixedTone: tone, tonalPalette: palette }); this.colors.push({ name: `on-${name}`, fixedTone: 15, tonalPalette: palette }); this.colors.push({ name: `${name}-container`, fixedTone: 90, tonalPalette: palette }); this.colors.push({ name: `on-${name}-container`, fixedTone: 15, tonalPalette: palette }); return this; } setCssClass(cssClass) { this.cssClass = cssClass; return this; } ensureCssClassStartsWithDot() { if (!this.cssClass || this.cssClass.startsWith('.')) { return; } this.cssClass = `.${this.cssClass}`; } ensureThemeColors() { if (!this.colors.find(c => c.name === 'secondary')) { this.addColorFromPalette('secondary', this.#corePalette.a2); } if (!this.colors.find(c => c.name === 'tertiary')) { this.addColorFromPalette('tertiary', this.#corePalette.a3); } } ensureStatusColors() { if (!this.colors.find(c => c.name === 'success')) { this.addStaticColor('success', '#198754', 60); } if (!this.colors.find(c => c.name === 'info')) { this.addStaticColor('info', '#0dcaf0'); } if (!this.colors.find(c => c.name === 'warning')) { this.addStaticColor('warning', '#ffc107'); } if (!this.colors.find(c => c.name === 'error')) { this.addColorFromHex('error', '#b3261e'); } } getNeutralVariables() { const builder = CssVarBuilder.create(); this.addColors(builder, neutralColors, this.#corePalette.n1); builder .add('--u-color-body', 'var(--u-color-surface)') .add('--u-color-inverse-body', 'var(--u-color-inverse-surface)') .add('--u-color-on-body', 'var(--u-color-on-surface)') .add('--u-color-on-inverse-body', 'var(--u-color-on-inverse-surface)') .add('--u-current-text-color', 'var(--u-color-on-body)'); return builder.build(); } getNeutralVariantVariables() { const builder = CssVarBuilder.create(); this.addColors(builder, neutralVariantColors, this.#corePalette.n2); return builder.build(); } getColorVariables(color) { const builder = CssVarBuilder.create(); this.addToneColor(builder, color, color.tonalPalette); return builder.build(); } getColorsVariables() { let variables = ''; for (const color of this.colors) { variables += this.getColorVariables(color); } variables += this.getNeutralVariables(); variables += this.getNeutralVariantVariables(); return variables; } addColors(builder, colors, palette) { for (const color of colors) { this.addToneColor(builder, color, palette); } } addToneColor(builder, color, palette) { if (color.fixedTone !== undefined) { builder.addFromArgb(color.name, palette.tone(color.fixedTone)); return; } const inverseName = `inverse-${color.name}`.replace('inverse-on', 'on-inverse'); builder .addLightAndDarkFromArgb(color.name, palette.tone(color.lightTone), palette.tone(color.darkTone)) .addLightAndDarkFromArgb(inverseName, palette.tone(color.darkTone), palette.tone(color.lightTone)); if (color.name === 'surface' || color.name === 'on-surface') { const prefix = color.name.startsWith('on-') ? 'on-' : ''; builder.addFromArgb(`${prefix}light-surface`, palette.tone(color.lightTone)); builder.addFromArgb(`${prefix}dark-surface`, palette.tone(color.darkTone)); } } build() { this.ensureCssClassStartsWithDot(); const selector = this.cssClass ?? ':root'; this.ensureThemeColors(); if (!this.partial) { this.ensureStatusColors(); } const variables = `${getCss(selector, this.getColorsVariables())} `; return variables; } } //# sourceMappingURL=theme-builder.js.map