UNPKG

@nex-ui/system

Version:

A lightweight and performant styling library based on Emotion, focusing on component architecture and developer experience.

108 lines (105 loc) 4.41 kB
import { isPlainObject, walkObject, merge, get } from '@nex-ui/utils'; import { memoizeFn, isSelector } from './utils.mjs'; const isCustomSelector = (key)=>{ return key.startsWith('_') && key !== '_DEFAULT'; }; const createCssFn = ({ normalize, isAlias, getCustomizedSelector })=>{ const css = (interpolation)=>{ if (!interpolation) { return ''; } // TODO: unused const componentSelector = interpolation; if (componentSelector.__emotion_styles !== undefined) { return componentSelector; } if (Array.isArray(interpolation)) { const arrayInterpolation = interpolation; return arrayInterpolation.map((v)=>css(v)); } if (isPlainObject(interpolation)) { const keyframes = interpolation; if (keyframes.anim === 1) { return keyframes; } // TODO: unused const serializedStyles = interpolation; if (serializedStyles.styles !== undefined) { return serializedStyles; } const cssOjbect = interpolation; const handlePath = (path)=>{ return path.filter((v)=>v !== '_DEFAULT').sort((a)=>{ // Filter out _DEFAULT first, ensure that those starting with letters are in front, // and those starting with _ are at the back, to support suffix selectors const charCode = a.charCodeAt(0); if (charCode > 64 && charCode < 91) { return -1; } return 96 - a.charCodeAt(0); }).map((p)=>{ // 0 - 9 if (p.charCodeAt(0) > 47 && p.charCodeAt(0) < 58) { const part = path.slice(0, path.length - 1); const prevValue = get(cssOjbect, part); const index = Number(p); if (!Number.isNaN(index) && Array.isArray(prevValue)) { // Handle array breakpoints return getCustomizedSelector(`_${index}`) ?? ''; } } // Handle custom selectors and object breakpoints return isCustomSelector(p) ? getCustomizedSelector(p) ?? p : p; }); }; const getColorPalette = (path)=>{ if (path.length === 0) { return cssOjbect['colorPalette']; } return get(cssOjbect, [ ...path, 'colorPalette' ], getColorPalette(path.slice(0, path.length - 1))); }; const result = {}; walkObject(cssOjbect, (propValue, path)=>{ if (Array.isArray(propValue)) { const selectors = path.map((p)=>isCustomSelector(p) ? getCustomizedSelector(p) ?? p : p); const lastSelector = selectors[selectors.length - 1]; mergeByPath(result, selectors, css(propValue), (v)=>v === lastSelector ? [] : {}); return; } const prefix = path.slice(0, path.length - 1); if (path[path.length - 1] === 'colorPalette') { return; } const colorPalette = getColorPalette(prefix); const [propKey, ...selectors] = handlePath(path); const normalized = normalize({ propKey, propValue, colorPalette }); mergeByPath(result, selectors, normalized); }, { predicate: (v, path)=>{ const key = path[path.length - 2]; return Array.isArray(v) && !isAlias(key) && (isCustomSelector(key) || isSelector(key)); } }); return result; } return interpolation; }; return memoizeFn(css); }; function mergeByPath(target, path, value, customizer) { let acc = target; path.forEach((k)=>{ if (!k) return; if (!acc[k]) acc[k] = customizer ? customizer(k) : {}; acc = acc[k]; }); return merge(acc, value); } export { createCssFn };