substyle
Version:
Universal styling for reusable React components
90 lines (74 loc) • 5.28 kB
JavaScript
import _defineProperty from "@babel/runtime/helpers/defineProperty";
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
import invariant from 'invariant';
import coerceSelection from './coerceSelection';
import defaultPropsDecorator from './defaultPropsDecorator';
import { isElement, isModifier } from './filterKeys';
import memoize from './memoize';
import { hoistModifierStylesRecursive, pickNestedStyles } from './pickStyles';
import { compact, isPlainObject, keys, merge, values } from './utils';
var guessBaseClassName = function guessBaseClassName(classNames) {
// all class names must start with the same prefix: the component's base class name
// which will finally go to the container element
var firstKey = classNames && keys(classNames)[0];
return firstKey && firstKey.split('__')[0].split('--')[0];
};
var deriveClassNames = function deriveClassNames(className, elementKeys, modifierKeys) {
// do not derive class names, if the user did not specify any class name
if (!className) {
return undefined;
} // derive class names based using the passed modifier/element keys
var firstClassName = className.split(' ')[0];
var derivedClassNames = [].concat(_toConsumableArray(elementKeys.length === 0 ? modifierKeys.map(function (key) {
return "".concat(firstClassName, "--").concat(key.substring(1));
}) : []), _toConsumableArray(elementKeys.map(function (key) {
return "".concat(firstClassName, "__").concat(key);
}))); // also use the provided `className` if there is no sub-element selection
return elementKeys.length === 0 ? [className].concat(_toConsumableArray(derivedClassNames)) : derivedClassNames;
};
function createSubstyle(_ref) {
var style = _ref.style,
className = _ref.className,
classNames = _ref.classNames;
var propsDecorator = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultPropsDecorator;
var baseClassName = className || guessBaseClassName(classNames) || (style === null || style === void 0 ? void 0 : style.className);
var substyle = typeof style === 'function' ? style : memoize(function (select, defaultStyle) {
var selectedKeys = coerceSelection(select);
invariant(Array.isArray(selectedKeys), 'First parameter must be a string, an array of strings, ' + 'a plain object with boolean values, or a falsy value.');
invariant(!defaultStyle || isPlainObject(defaultStyle), 'Optional second parameter must be a plain object.');
var modifierKeys = selectedKeys.filter(isModifier);
var elementKeys = selectedKeys.filter(isElement);
var collectElementStyles = elementKeys.length > 0 ? function (fromStyle) {
return values(pickNestedStyles(fromStyle, elementKeys));
} : function (fromStyle) {
return [fromStyle];
};
var collectSelectedStyles = function collectSelectedStyles() {
var fromStyle = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
return collectElementStyles(hoistModifierStylesRecursive(fromStyle, modifierKeys));
};
var derivedClassNames = deriveClassNames(baseClassName, elementKeys, modifierKeys);
return createSubstyle(_objectSpread(_objectSpread(_objectSpread({}, (style || defaultStyle) && {
style: merge.apply(void 0, [{}].concat(_toConsumableArray(collectSelectedStyles(defaultStyle)), _toConsumableArray(collectSelectedStyles(style))))
}), derivedClassNames && {
className: derivedClassNames.join(' ')
}), classNames && {
classNames: classNames
}), propsDecorator);
});
var styleProps = _objectSpread({}, typeof style === 'function' ? style : {
style: style
});
var classNameSplit = _toConsumableArray(new Set([].concat(_toConsumableArray(styleProps.className ? styleProps.className.split(' ') : []), _toConsumableArray(baseClassName ? baseClassName.split(' ') : []))));
var mappedClassNames = classNames ? compact(classNameSplit.map(function (singleClassName) {
return classNames[singleClassName];
})) : classNameSplit;
var propsForSpread = propsDecorator(_objectSpread(_objectSpread({}, styleProps), mappedClassNames.length > 0 ? {
className: mappedClassNames.join(' ')
} : {})); // assign `style`, `className`, and/or any props added by the decorator to the return function object
Object.assign(substyle, propsForSpread);
return substyle;
}
export default createSubstyle;