bsl
Version:
基于React的框架和UI组件
111 lines (95 loc) • 3.38 kB
text/typescript
import { prefix } from 'inline-style-prefixer';
import randomString from '../../utils/randomString';
import { CSSProperties } from './type';
export type StyleDeclarationMap = Map<keyof CSSProperties, string | number>;
export type SheetDefinition<T> = {
[P in keyof T]: CSSProperties | StyleDeclarationMap;
};
type Callback = (rule: string, value: string) => void;
const UPPERCASE_RE = /([A-Z])/g;
const UPPERCASE_RE_TO_KEBAB = (match: string): string => `-${match.toLowerCase()}`;
function kebabifyStyleName(string: string) {
const result = string.replace(UPPERCASE_RE, UPPERCASE_RE_TO_KEBAB);
if (result[0] === 'm' && result[1] === 's' && result[2] === '-') {
return `-${result}`;
}
return result;
};
/** 是否是伪类 */
function isPseudo(key: string) {
const firstChar = key[0];
if (firstChar === ':') {
return true;
}
return false;
}
/**
* 把驼峰命名转换成CSS的规则命名
* 判断规则是否是伪类,如果是伪类则处理成类名
* */
function cssRuleFormat(clsName: string, rule: string) {
const format = kebabifyStyleName(rule);
if (isPseudo(format)) {
return clsName + format;
} else {
return format;
}
}
/** 把对象拍平,取出伪类,只支持2层嵌套 */
function flatten<T>(sheetDefinition: SheetDefinition<T>): SheetDefinition<T> {
const newSheet: any = {};
const sheetDefinitionKeys = Object.keys(sheetDefinition);
for (let i = 0; i < sheetDefinitionKeys.length; i++) {
const wrapKey = sheetDefinitionKeys[i];
const wrap = sheetDefinition[wrapKey as keyof typeof sheetDefinition] as any;
const clsName = `${wrapKey}-${randomString(6)}-${Date.now()}`;
const wrapKeys = Object.keys(wrap);
for (let j = 0;j < wrapKeys.length; j++) {
const rule = wrapKeys[j];
if (isPseudo(rule)) {
newSheet[clsName + rule] = Object.assign({}, wrap[rule]);
delete wrap[rule];
}
}
newSheet[clsName] = sheetDefinition[wrapKey as keyof typeof sheetDefinition];
sheetDefinition[wrapKey as keyof typeof sheetDefinition] = clsName as any;
}
return newSheet as SheetDefinition<T>;
}
function each(cssProperties: CSSProperties, callback: Callback) {
const keys = Object.keys(cssProperties);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const item = cssProperties[key];
if (typeof item === 'object' && Array.isArray(item) === false) {
each(item as any, callback);
} else {
callback(key, cssProperties[key] as string);
}
}
}
function parser<T>(sheetDefinition: SheetDefinition<T>) {
const newSheet = flatten(sheetDefinition);
const keys = Object.keys(newSheet);
let css = '';
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const wrap = newSheet[key as keyof typeof sheetDefinition];
const rules: string[] = [];
const stylePrefix = prefix(wrap);
each(stylePrefix as any, (rule, value) => {
if (Array.isArray(value)) {
value.forEach((item) => {
rules.push(`${cssRuleFormat(key, rule)}: ${item}`);
});
} else {
rules.push(`${cssRuleFormat(key, rule)}: ${value}`);
}
});
css += `
.${key} { ${rules.join(';')} }
`;
}
return css;
}
export default parser;