mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2025-12-15 14:00:35 +00:00
217 lines
4.9 KiB
TypeScript
217 lines
4.9 KiB
TypeScript
/**
|
|
* just for legao
|
|
* @author: jiushen
|
|
*/
|
|
// 需要通过 Env 来判断是否需要
|
|
|
|
import { some } from 'lodash';
|
|
|
|
const pseudoMap = ['hover', 'focus', 'active', 'visited'];
|
|
|
|
const RE_CAMEL = /[A-Z]/g;
|
|
const RE_HYPHEN = /[-\s]+(.)?/g;
|
|
const PROPS_REG = /([^:]*):\s?(.*)/i;
|
|
|
|
// 给 css 分组
|
|
function groupingCss(css: string) {
|
|
let stackLength = 0;
|
|
let startIndex = 0;
|
|
const group: string[] = [];
|
|
css.split('').forEach((char, index) => {
|
|
if (char === '{') {
|
|
stackLength++;
|
|
}
|
|
if (char === '}') {
|
|
if (stackLength === 1) {
|
|
group.push(css.substring(startIndex, index + 1));
|
|
startIndex = index + 1;
|
|
}
|
|
stackLength--;
|
|
}
|
|
});
|
|
return group;
|
|
}
|
|
|
|
function isString(str: any): str is string {
|
|
return {}.toString.call(str) === '[object String]';
|
|
}
|
|
|
|
function hyphenate(str: string): string {
|
|
return str.replace(RE_CAMEL, w => `-${w}`).toLowerCase();
|
|
}
|
|
|
|
function camelize(str: string): string {
|
|
return str.replace(RE_HYPHEN, (m, w) => (w ? w.toUpperCase() : ''));
|
|
}
|
|
|
|
/**
|
|
* convert
|
|
* {background-color: "red"}
|
|
* to
|
|
* background-color: red;
|
|
*/
|
|
function runtimeToCss(runtime: Record<string, string>) {
|
|
const css: string[] = [];
|
|
Object.keys(runtime).forEach((key) => {
|
|
css.push(` ${key}: ${runtime[key]};`);
|
|
});
|
|
return css.join('\n');
|
|
}
|
|
|
|
function toNativeStyle(runtime: Record<string, string> | undefined) {
|
|
if (!runtime) {
|
|
return {};
|
|
}
|
|
if (runtime.default) {
|
|
const normalized: Record<string, string> = {};
|
|
Object.keys(runtime).forEach((pseudo) => {
|
|
if (pseudo === 'extra') {
|
|
normalized[pseudo] = runtime[pseudo];
|
|
return;
|
|
}
|
|
normalized[pseudo] = toNativeStyle(runtime[pseudo]);
|
|
});
|
|
return normalized;
|
|
}
|
|
|
|
const normalized = {};
|
|
Object.keys(runtime).forEach((key) => {
|
|
normalized[camelize(key)] = runtime[key];
|
|
});
|
|
return normalized;
|
|
}
|
|
|
|
function normalizeStyle(style) {
|
|
if (!style) {
|
|
return {};
|
|
}
|
|
if (style.default) {
|
|
const normalized = {};
|
|
Object.keys(style).forEach((pseudo) => {
|
|
if (pseudo === 'extra') {
|
|
normalized[pseudo] = style[pseudo];
|
|
return;
|
|
}
|
|
normalized[pseudo] = normalizeStyle(style[pseudo]);
|
|
});
|
|
return normalized;
|
|
}
|
|
|
|
const normalized: Record<string, string | Record<string, string>> = {};
|
|
Object.keys(style).forEach((key) => {
|
|
normalized[hyphenate(key)] = style[key];
|
|
});
|
|
return normalized;
|
|
}
|
|
|
|
function toCss(runtime) {
|
|
if (!runtime) {
|
|
return (
|
|
`:root {
|
|
|
|
}`);
|
|
}
|
|
|
|
if (runtime.default) {
|
|
const css: string[] = [];
|
|
Object.keys(runtime).forEach((pseudo) => {
|
|
if (pseudo === 'extra') {
|
|
Array.isArray(runtime.extra) && css.push(runtime.extra.join('\n'));
|
|
return;
|
|
}
|
|
// 只需要对这四种做兼容
|
|
const prefix = pseudoMap.indexOf(pseudo) > -1 ? ':' : '';
|
|
css.push(
|
|
`:root${pseudo === 'default' ? '' : `${prefix}${pseudo}`} {
|
|
${runtimeToCss(normalizeStyle(runtime[pseudo]))}
|
|
}\n`,
|
|
);
|
|
});
|
|
return css.join('\n');
|
|
}
|
|
|
|
return (
|
|
`:root {
|
|
${runtimeToCss(normalizeStyle(runtime))}
|
|
}
|
|
`
|
|
);
|
|
}
|
|
|
|
function cssToRuntime(css: string) {
|
|
if (!css) {
|
|
return {};
|
|
}
|
|
const runtime: {
|
|
extra?: string[];
|
|
default?: Record<string, string>;
|
|
} = {};
|
|
const groups = groupingCss(css);
|
|
groups.forEach((cssItem) => {
|
|
if (!cssItem.startsWith(':root')) {
|
|
runtime.extra = runtime.extra || [];
|
|
runtime.extra.push(cssItem.trim());
|
|
} else {
|
|
const res = /:root:?(.*)?{(.*)/ig.exec(cssItem.replace(/[\r\n]+/ig, '').trim());
|
|
if (res) {
|
|
let pseudo: string | undefined;
|
|
|
|
if (res[1] && res[1].trim() && some(pseudoMap, pse => res[1].indexOf(pse) === 0)) {
|
|
pseudo = res[1].trim();
|
|
} else if (res[1] && res[1].trim()) {
|
|
pseudo = res[1];
|
|
}
|
|
|
|
const s: Record<string, string> = {};
|
|
res[2].split(';').reduce<string[]>((prev, next) => {
|
|
if (next.indexOf('base64') > -1) {
|
|
prev[prev.length - 1] += `;${next}`;
|
|
} else {
|
|
prev.push(next);
|
|
}
|
|
return prev;
|
|
}, []).forEach((item) => {
|
|
if (item) {
|
|
if (PROPS_REG.test(item)) {
|
|
const props = item.match(PROPS_REG);
|
|
const key = props?.[1];
|
|
const value = props?.[2];
|
|
if (key && value) {
|
|
s[key.trim()] = value.trim();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
runtime[pseudo || 'default'] = s;
|
|
}
|
|
}
|
|
});
|
|
return runtime;
|
|
}
|
|
|
|
function cssToStyle(css) {
|
|
try {
|
|
if (isString(css)) {
|
|
return toNativeStyle(cssToRuntime(css).default);
|
|
}
|
|
if (css.default) {
|
|
return toNativeStyle(normalizeStyle(css.default));
|
|
}
|
|
return toNativeStyle(normalizeStyle(css));
|
|
} catch (e) {
|
|
// do nothing
|
|
}
|
|
return {};
|
|
}
|
|
|
|
export {
|
|
hyphenate,
|
|
camelize,
|
|
toNativeStyle,
|
|
normalizeStyle,
|
|
toCss,
|
|
cssToRuntime,
|
|
cssToStyle,
|
|
};
|