@quarkly/atomize
Version:
Library for creating atomic react components
287 lines (261 loc) • 8.69 kB
JavaScript
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
};
};
});