UNPKG

@quarkly/atomize

Version:

Library for creating atomic react components

287 lines (261 loc) 8.69 kB
import _extends from "@babel/runtime/helpers/esm/extends"; import _camelCase from "lodash/camelCase"; import _sortBy from "lodash/sortBy"; import _memoize from "lodash/memoize"; import _get from "lodash/get"; import _merge from "lodash/merge"; import _flow from "lodash/flow"; import dict, { hashPropsWithAliases } from '../constants/dict'; import { themeProps, themePrefixes } from '../constants/theme'; import { themeGet, getBreakpoints } from '../utils/theme'; import splitCSSRule from './split-css-rule'; import validate from '../utils/validate'; import transformers, { defaultTransformer } from '../utils/transformers'; import { variants, themed, mixins } from '../utils/modifiers'; import { searchRuleInKey as searchRule, searchBreakpointInKey, searchEffectInKey } from './search-rule'; export var getTransformer = function getTransformer(name) { return _get(transformers, name, defaultTransformer); }; export var getThemePrefix = function getThemePrefix(key) { if (key.endsWith('-color')) return 'color'; if (themeProps.includes(key)) return _camelCase(key); return ''; }; export var trimComma = function trimComma(value) { if (typeof value !== 'string') return value; return splitCSSRule(value).filter(function (v) { return v; }).join(','); }; export var testExistPrefix = function testExistPrefix(name) { var splited = name.split('-') || []; if (splited.length <= 1) return false; return themePrefixes.includes(splited[0]); }; export var transformVar = function transformVar(key, value) { if (typeof value !== 'string' || value.indexOf('--') === -1) return value; var prefix = getThemePrefix(key); return value.replace(/(^|\s|,|calc\()(?:var\()?--([^,\s]*)/gi, function (res, before, name) { if (res.includes('var(')) return res; if (prefix && !testExistPrefix(name)) return before + "var(--qtheme-" + prefix + "-" + name + ")"; return before + "var(--qtheme-" + name + ")"; }); }; export var ruleExists = function ruleExists(key, config) { if (!config) return hashPropsWithAliases[key]; if (config.useAliases) return hashPropsWithAliases[key]; return dict[key]; }; export var createCssRule = function createCssRule(_ref) { var propKey = _ref.propKey, value = _ref.value, props = _ref.props, config = _ref.config; var currentKey = propKey[0], otherKeys = propKey.slice(1); if (!ruleExists(currentKey, config)) return {}; var _hashPropsWithAliases = hashPropsWithAliases[currentKey], transformer = _hashPropsWithAliases.transformer, compose = _hashPropsWithAliases.compose; var transform = getTransformer(transformer); var createCss = function createCss(n, key) { var _ref2; var resultValue = trimComma(transformVar(key, transform(n, []))); var isValid = typeof resultValue === 'string' ? validate(resultValue) : true; if (!isValid) return null; return _ref2 = {}, _ref2[key] = resultValue, _ref2; }; var css = compose ? compose.reduce(function (acc, composeKey) { var cCss = createCss(value, composeKey); return _merge(acc, cCss); }, {}) : createCss(value, hashPropsWithAliases[currentKey].name); return { propKey: otherKeys, value: value, css: css, props: props, config: config }; }; export var createEffectWrapper = function createEffectWrapper(_ref3) { var _newCss; var propKey = _ref3.propKey, value = _ref3.value, props = _ref3.props, css = _ref3.css, config = _ref3.config; if (!css) return {}; var currentKey = propKey[0], otherKeys = propKey.slice(1); var effects = config.effects; if (!effects) { return { propKey: propKey, value: value, css: css, props: props, config: config }; } var effectNames = Object.keys(effects); if (!effectNames || !effectNames.length) { return { propKey: propKey, value: value, css: css, props: props, config: config }; } // текущий ключ - не медиа выражение if (!effects[currentKey]) { return { propKey: propKey, value: value, css: css, props: props, config: config }; } var effectCssKey = effects[currentKey]; var newCss = (_newCss = {}, _newCss["&" + effectCssKey + ", &[data-quarkly-state=\"" + currentKey + "\"]"] = css, _newCss); return { propKey: otherKeys, value: value, css: newCss, props: props, config: config }; }; export var createMediaWrapper = function createMediaWrapper(_ref4) { var _newCss2; var propKey = _ref4.propKey, value = _ref4.value, props = _ref4.props, css = _ref4.css, config = _ref4.config; if (!css) return {}; var currentKey = propKey[0]; var breakpoints = getBreakpoints(props); if (!breakpoints[currentKey]) return { propKey: propKey, value: value, css: css, props: props, config: config }; var mediaSelector = breakpoints[currentKey]; var newCss = (_newCss2 = {}, _newCss2[mediaSelector] = css, _newCss2); return { propKey: currentKey, value: value, css: newCss, config: config }; }; export var createStyleRule = _flow([createCssRule, createEffectWrapper, createMediaWrapper]); export var createOverriderStyles = function createOverriderStyles(overriders) { return function (props) { return overriders.reduce(function (acc, ov) { return _merge(acc, ov(props)); }, {}); }; }; export var replaceKey = function replaceKey(key, replaced) { return key.replace(replaced, '').split('-').filter(function (a) { return a; }).join('-'); }; var createChunks = function createChunks(props, config) { return Object.entries(props).reduce(function (acc, _ref5) { var key = _ref5[0], value = _ref5[1]; var ruleChain = searchRule(key); if (!ruleChain) return acc; key = replaceKey(key, ruleChain); var effectChain = searchEffectInKey(key, config.effects || {}); if (effectChain) { key = replaceKey(key, effectChain); } var breakpoints = themeGet(props, 'breakpoints', {}); var breackpointChain = searchBreakpointInKey(key, breakpoints); acc.push({ chains: { ruleChain: ruleChain, breackpointChain: breackpointChain, effectChain: effectChain }, value: value }); return acc; }, []); }; export var createChainStream = function createChainStream(chains) { var ruleChain = chains.ruleChain, effectChain = chains.effectChain, breackpointChain = chains.breackpointChain; var listChains = [ruleChain, effectChain, breackpointChain]; return listChains.filter(function (a) { return a; }); }; export var getSortedBreakpoints = _memoize(function (breakpoints) { return _sortBy(Object.entries(breakpoints), function (_ref6) { var _ref6$ = _ref6[1], item = _ref6$[0]; return item.type === 'max-width' ? -1 : 1; }, function (_ref7) { var _ref7$ = _ref7[1], item = _ref7$[0]; return item.value * (item.type === 'max-width' ? -1 : 1); }); }); export var sortByBreakpointsOrder = function sortByBreakpointsOrder(chunks, props) { var sortedBreakpoints = getSortedBreakpoints(themeGet(props, 'breakpoints')); return _sortBy(chunks, function (_ref8) { var chains = _ref8.chains; return sortedBreakpoints.findIndex(function (_ref9) { var key = _ref9[0]; return key === chains.breackpointChain; }); }); }; export default (function (config, defaultProps) { if (defaultProps === void 0) { defaultProps = {}; } return function (componentProps) { var props = _extends(_extends({}, defaultProps), componentProps); var deps = []; if (config.name) { deps.push(themed(config.name)); } if (config.variant) { deps.push(variants(config.variant)); } if (config.mixins) { deps.push(mixins); } // apply styles in breakpoints order var overrider = createOverriderStyles(deps); var chunks = sortByBreakpointsOrder(createChunks(props, config), props); var cleanedProps = _extends({}, props); var cssObject = chunks.reduce(function (acc, _ref10) { var chains = _ref10.chains, value = _ref10.value; var propKey = createChainStream(chains); var _createStyleRule = createStyleRule({ propKey: propKey, value: value, props: props, config: config }), css = _createStyleRule.css; if (!css) return acc; delete cleanedProps[propKey.reverse().join('-')]; return _merge(acc, css); }, overrider(props)); return { cssObject: cssObject, cleanedProps: cleanedProps }; }; });