UNPKG

@nex-ui/system

Version:

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

118 lines (115 loc) 3.62 kB
import { mergeWith, isArray, isPlainObject, isString, every, memoize, isNumber } from '@nex-ui/utils'; import serialize from '@x1ngyu/serialize-javascript'; function pathToTokenName(path) { return path.join('.'); } function camelToKebab(str) { return str.replace(/([A-Z])/g, (match)=>{ return `-${match.toLowerCase()}`; }); } function isDecimalString(str) { return /^\d+\.\d+$/.test(str); } function createCssVarName(prefix, path) { return `--${prefix}-${path.map((k)=>{ if (isDecimalString(k)) { return k.split('.').join('-'); } return camelToKebab(k); }).join('-')}`; } function isResponsiveColor(value) { return isPlainObject(value) && (value._light || value._dark || value._DEFAULT); } function isValidTokenValue(value) { if (!isString(value) && !isNumber(value)) { return false; } return true; } function isValidSemanticTokenValue(value) { if (!isString(value) && !isNumber(value) && !isResponsiveColor(value)) { return false; } return true; } function isValidTokenCategory(category) { if (!isString(category)) { return false; } switch(category){ case 'colors': case 'fontFamilies': case 'fontSizes': case 'fontWeights': case 'sizes': case 'spaces': case 'lineHeights': case 'borders': case 'radii': case 'breakpoints': case 'shadows': case 'transitions': case 'borderWidths': case 'zIndexes': return true; default: return false; } } function isValidAliasValue(value) { if (isString(value) || isArray(value) && every(value, isString)) { return true; } return false; } function isValidBreakpointValue(value) { if (isString(value) && parseInt(value, 10) >= 0) { return true; } return false; } function memoizeFn(fn) { return memoize(fn, (...args)=>serialize(args)); } function extractTokenPlaceholders(value) { const regex = /\{(.*?)\}/g; const matches = value.matchAll(regex); return [ ...matches ]; } // TODO 明确 CSS 合并规则 function mergeRecipeConfigs(...args) { const recipes = JSON.parse(JSON.stringify(args)); return mergeWith({}, ...recipes, (targetValue, srcValue, key)=>{ if (key === 'compoundVariants') { if (targetValue === undefined) { return srcValue; } if (isArray(targetValue) && isArray(srcValue)) { return [ ...targetValue, ...srcValue ]; } } if (typeof targetValue !== typeof srcValue || isArray(targetValue) !== isArray(srcValue) || isPlainObject(targetValue) !== isPlainObject(srcValue)) { return srcValue; } }); } const toExpression = (operator, ...operands)=>operands.map(String).join(` ${operator} `).replace(/calc/g, ''); const multiply = (...operands)=>`calc(${toExpression('*', ...operands)})`; const negate = (x)=>{ const value = String(x); if (value != null && !Number.isNaN(parseFloat(value))) { if (Number(value) === 0) { return '0'; } return value.startsWith('-') ? value.slice(1) : `-${value}`; } return multiply(value, -1); }; export { createCssVarName, extractTokenPlaceholders, isResponsiveColor, isValidAliasValue, isValidBreakpointValue, isValidSemanticTokenValue, isValidTokenCategory, isValidTokenValue, memoizeFn, mergeRecipeConfigs, multiply, negate, pathToTokenName };