mdui
Version:
实现 material you 设计规范的 Web Components 组件库
134 lines (130 loc) • 5.35 kB
JavaScript
import { blueFromArgb, greenFromArgb, redFromArgb, customColor, argbFromHex, Scheme, CorePalette, } from '@material/material-color-utilities';
import { getDocument } from 'ssr-window';
import { $ } from '@mdui/jq/$.js';
import { unique } from '@mdui/jq/functions/unique.js';
import '@mdui/jq/methods/addClass.js';
import '@mdui/jq/methods/append.js';
import '@mdui/jq/methods/get.js';
import '@mdui/jq/methods/remove.js';
import '@mdui/jq/methods/removeClass.js';
import { toKebabCase } from '@mdui/jq/shared/helper.js';
const themeArr = ['light', 'dark'];
const prefix = 'mdui-custom-color-scheme-'; // 类名前缀
let themeIndex = 0;
const rgbFromArgb = (source) => {
const red = redFromArgb(source);
const green = greenFromArgb(source);
const blue = blueFromArgb(source);
return [red, green, blue].join(', ');
};
/**
* 移除指定元素上的配色方案
* @param target
*/
export const remove = (target) => {
const $target = $(target);
// 找出指定元素上所有的配色方案 CSS class
let classNames = $target
.get()
.map((element) => Array.from(element.classList))
.flat();
classNames = unique(classNames).filter((className) => className.startsWith(prefix));
// 移除 CSS class
$target.removeClass(classNames.join(' '));
// 找出没有被其他元素使用的 CSS class
const unusedClassNames = classNames.filter((className) => $(`.${className}`).length === 0);
// 移除对应的 <style> 元素
$(unusedClassNames.map((i) => `#${i}`).join(',')).remove();
};
/**
* 设置配色方案
* 在 head 中插入一个 <style id="mdui-custom-color-scheme-${source}"> 元素,
* 并在 target 元素上添加 class="mdui-custom-color-scheme-${source}"
*
* 自定义颜色的 css 变量
* --mdui-color-red
* --mdui-color-on-red
* --mdui-color-red-container
* --mdui-color-on-red-container
*
* @param source
* @param options
*/
export const setFromSource = (source, options) => {
const document = getDocument();
const $target = $(options?.target || document.documentElement);
// 生成配色方案
const schemes = {
light: Scheme.light(source).toJSON(),
dark: Scheme.dark(source).toJSON(),
};
// todo 目前 @material/material-color-utilities 库缺失了 8 种颜色,等官方库加上后,可以删除这段代码
// https://github.com/material-foundation/material-color-utilities/issues/98
const palette = CorePalette.of(source);
Object.assign(schemes.light, {
'surface-dim': palette.n1.tone(87),
'surface-bright': palette.n1.tone(98),
'surface-container-lowest': palette.n1.tone(100),
'surface-container-low': palette.n1.tone(96),
'surface-container': palette.n1.tone(94),
'surface-container-high': palette.n1.tone(92),
'surface-container-highest': palette.n1.tone(90),
'surface-tint-color': schemes.light.primary,
});
Object.assign(schemes.dark, {
'surface-dim': palette.n1.tone(6),
'surface-bright': palette.n1.tone(24),
'surface-container-lowest': palette.n1.tone(4),
'surface-container-low': palette.n1.tone(10),
'surface-container': palette.n1.tone(12),
'surface-container-high': palette.n1.tone(17),
'surface-container-highest': palette.n1.tone(22),
'surface-tint-color': schemes.dark.primary,
});
// 扩充自定义颜色
(options?.customColors || []).map((color) => {
const name = toKebabCase(color.name);
const custom = customColor(source, {
name,
value: argbFromHex(color.value),
blend: true,
});
themeArr.forEach((theme) => {
schemes[theme][name] = custom[theme].color;
schemes[theme][`on-${name}`] = custom[theme].onColor;
schemes[theme][`${name}-container`] = custom[theme].colorContainer;
schemes[theme][`on-${name}-container`] = custom[theme].onColorContainer;
});
});
// 根据配色方案生成 css 变量
const colorVar = (theme, callback) => {
return Object.entries(schemes[theme])
.map(([key, value]) => callback(toKebabCase(key), rgbFromArgb(value)))
.join('');
};
const className = prefix + `${source}-${themeIndex++}`;
// CSS 文本
const cssText = `.${className} {
${colorVar('light', (token, rgb) => `--mdui-color-${token}-light: ${rgb};`)}
${colorVar('dark', (token, rgb) => `--mdui-color-${token}-dark: ${rgb};`)}
${colorVar('light', (token) => `--mdui-color-${token}: var(--mdui-color-${token}-light);`)}
color: rgb(var(--mdui-color-on-background));
background-color: rgb(var(--mdui-color-background));
}
.mdui-theme-dark .${className},
.mdui-theme-dark.${className} {
${colorVar('dark', (token) => `--mdui-color-${token}: var(--mdui-color-${token}-dark);`)}
}
@media (prefers-color-scheme: dark) {
.mdui-theme-auto .${className},
.mdui-theme-auto.${className} {
${colorVar('dark', (token) => `--mdui-color-${token}: var(--mdui-color-${token}-dark);`)}
}
}`;
// 移除旧的配色方案
remove($target);
// 创建 <style> 元素,添加到 head 中
$(document.head).append(`<style id="${className}">${cssText}</style>`);
// 添加新配色方案
$target.addClass(className);
};