@weareredlight/components
Version:
> TODO: description
453 lines (367 loc) • 19.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.buildScreen = exports.themeBuilder = exports.themeParser = exports.mergeWithComponentStyles = exports.mergeStyles = void 0;
var _reactNative = require("react-native");
var _set = _interopRequireDefault(require("lodash/set"));
var _get = _interopRequireDefault(require("lodash/get"));
var _merge = _interopRequireDefault(require("lodash/merge"));
var _flatten = _interopRequireDefault(require("lodash/flatten"));
var _cloneDeep = _interopRequireDefault(require("lodash/cloneDeep"));
var _objFlatten = _interopRequireDefault(require("obj-flatten"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _iterableToArrayLimit(arr, i) { if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
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; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
var defaultANDseparator = '&';
var defaultORseparator = '|';
var defaultFunctions = '__fun';
var defaultMixins = '__mixins';
var defaultLandscape = {
__isLandscape: function __isLandscape(_ref) {
var _ref$window = _ref.window,
width = _ref$window.width,
height = _ref$window.height;
return width > height;
}
};
var defaultPlatforms = {
__android: function __android() {
return _reactNative.Platform.OS === 'android';
},
__ios: function __ios() {
return _reactNative.Platform.OS === 'ios';
},
__web: function __web() {
return _reactNative.Platform.OS === 'web';
},
__window: function __window() {
return _reactNative.Platform.OS === 'window';
},
__macos: function __macos() {
return _reactNative.Platform.OS === 'macos';
}
};
var defaultBreakPoints = {
__phone: function __phone(_ref2) {
var bp = _ref2.breakPoints;
return bp.phone;
},
__phablet: function __phablet(_ref3) {
var bp = _ref3.breakPoints;
return bp.phablet;
},
__tablet: function __tablet(_ref4) {
var bp = _ref4.breakPoints;
return bp.tablet;
},
__desktop: function __desktop(_ref5) {
var bp = _ref5.breakPoints;
return bp.desktop;
},
__desktopHD: function __desktopHD(_ref6) {
var bp = _ref6.breakPoints;
return bp.desktopHD;
},
__ltePhablet: function __ltePhablet(_ref7) {
var bp = _ref7.breakPoints;
return bp.ltePhablet;
},
__gtePhablet: function __gtePhablet(_ref8) {
var bp = _ref8.breakPoints;
return bp.gtePhablet;
},
__lteTablet: function __lteTablet(_ref9) {
var bp = _ref9.breakPoints;
return bp.lteTablet;
},
__gteTablet: function __gteTablet(_ref10) {
var bp = _ref10.breakPoints;
return bp.gteTablet;
},
__lteDesktop: function __lteDesktop(_ref11) {
var bp = _ref11.breakPoints;
return bp.lteDesktop;
},
__gteDesktop: function __gteDesktop(_ref12) {
var bp = _ref12.breakPoints;
return bp.gteDesktop;
}
};
var allTargets = _objectSpread(_objectSpread(_objectSpread({}, defaultLandscape), defaultPlatforms), defaultBreakPoints);
var mergeStyles = function mergeStyles(stylesList) {
return _merge["default"].apply(void 0, [{}].concat(_toConsumableArray(stylesList)));
};
exports.mergeStyles = mergeStyles;
var mergeWithComponentStyles = function mergeWithComponentStyles(theme, compName) {
var compStyles = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var styles = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
// STEP 1 - check if the user injected styles has functions in it
// we know compStyles doesn't have any because we solved them in themeParser()
var flattenUserStyles = (0, _objFlatten["default"])(styles);
var hasFunctions = Object.entries(flattenUserStyles).some(function (_ref13) {
var _ref14 = _slicedToArray(_ref13, 2),
key = _ref14[0],
value = _ref14[1];
return key.endsWith(defaultFunctions);
});
var solvedStyles = hasFunctions ? solveThemeFunctions(theme, _defineProperty({}, compName, styles))[compName] : styles; // STEP 2 - merge component styles and user styles
var mergedStyles = (0, _merge["default"])({}, compStyles, solvedStyles); // STEP 3 - parse final object to remove __targets
return parseThemeDeep(theme, _defineProperty({}, compName, mergedStyles))[compName];
};
exports.mergeWithComponentStyles = mergeWithComponentStyles;
var themeParser = function themeParser(theme, selectedTheme) {
var themeCopy = (0, _merge["default"])({}, {
// Things to keep from default theme
breakPoints: theme.breakPoints,
mixins: theme.mixins,
screen: theme.screen,
window: theme.window,
// Placeholder stuff
themes: theme.defaultThemes,
components: theme.defaultComponents
}); // STEP 1
// 1 - solve default themes functions
// 2 - solve user themes functions
// 3 - merge both styles
// 4 - parse styles
var solvedDefaultThemes = solveThemeFunctions(themeCopy, theme.defaultThemes);
themeCopy.themes = solvedDefaultThemes;
var solvedUserThemes = solveThemeFunctions(themeCopy, theme.userThemes);
var mergedThemes = (0, _merge["default"])({}, solvedDefaultThemes, solvedUserThemes);
var parsedThemes = parseThemeDeep(themeCopy, mergedThemes);
themeCopy.themes = parsedThemes;
themeCopy.vars = parsedThemes[selectedTheme]; // STEP 2
// 1 - solve default components functions
// 2 - solve user components functions
// 3 - merge both components
// 4 - parse components
var solvedDefaultComponents = solveThemeFunctions(themeCopy, theme.defaultComponents);
themeCopy.components = solvedDefaultComponents;
var solvedUserComponents = solveThemeFunctions(themeCopy, theme.userComponents);
var mergedComponents = (0, _merge["default"])({}, solvedDefaultComponents, solvedUserComponents);
var parsedComponents = parseThemeDeep(themeCopy, mergedComponents);
themeCopy.components = parsedComponents;
return themeCopy;
};
exports.themeParser = themeParser;
var parseThemeDeep = function parseThemeDeep(theme, list) {
var listCopy = {};
Object.entries(list).forEach(function (_ref15) {
var _ref16 = _slicedToArray(_ref15, 2),
name = _ref16[0],
props = _ref16[1];
var parse = function parse(data) {
return Object.entries(data).map(function (_ref17) {
var _ref18 = _slicedToArray(_ref17, 2),
propName = _ref18[0],
value = _ref18[1];
if (propName.startsWith('__')) {
if (propName === defaultFunctions) {
// __fun
if (value !== null) {
throw new Error("parseThemeDeep: ".concat(name, " ").concat(propName, " has a value (").concat(value, "),but it should be 'null'. Please check your theme."));
}
return null;
} else if (propName === defaultMixins && value !== null) {
// __mixins
if (_typeof(value) !== 'object') {
throw new Error("parseThemeDeep: ".concat(name, " ").concat(propName, " value is not an 'object' as expected.We got a ").concat(_typeof(value), " instead. Please check your theme."));
}
var mixinResults = Object.entries(value).map(function (_ref19) {
var _ref20 = _slicedToArray(_ref19, 2),
mixinName = _ref20[0],
mixinParams = _ref20[1];
var mixinFunc = theme.mixins[mixinName];
if (!mixinFunc || typeof mixinFunc !== 'function') {
throw new Error("parseThemeDeep: Mixin '".concat(mixinName, "' invalid. Please check your <ThemeProvider mixins>"));
}
return _merge["default"].apply(void 0, [{}].concat(_toConsumableArray(parse(mixinFunc.apply(void 0, [theme].concat(_toConsumableArray(mixinParams)))))));
});
return _merge["default"].apply(void 0, [{}].concat(_toConsumableArray(mixinResults)));
} // Logic key validation
// __android|__ios&__phone|__phablet
var shouldAddObject = propName.split(defaultANDseparator).reduce( // [ '__android|__ios', '__phone|__phablet' ]
function (acc, curr) {
return acc && curr.split(defaultORseparator).reduce( // [ [ '__android', '__ios' ], [ '__phone', '__phablet' ] ]
function (a, c) {
var validator = allTargets[c];
if (!validator) {
return a || true;
}
return a || validator(theme);
}, false);
}, true); // result = ( __android || __ios ) && ( __phone || __phablet )
if (shouldAddObject) {
// Dig deep! Recursive point
// This is why '__web&__desktop {}' is better than '__web { __desktop {} }'
return _merge["default"].apply(void 0, [{}].concat(_toConsumableArray(parse(value))));
}
return null;
} else if (_typeof(value) === 'object') {
// Dig deep! Recursive point
return _defineProperty({}, propName, _merge["default"].apply(void 0, [{}].concat(_toConsumableArray(parse(value)))));
} else {
return _defineProperty({}, propName, value);
}
});
};
var result = _merge["default"].apply(void 0, [{}].concat(_toConsumableArray(parse(props))));
listCopy[name] = result;
});
return listCopy;
};
var themeBuilder = function themeBuilder(themeDefaultTemplate, defaultThemeName, selectedTheme, breakPoints, variables, themes, components, mixins) {
return _objectSpread(_objectSpread({}, buildScreen({
window: _reactNative.Dimensions.get('window'),
screen: _reactNative.Dimensions.get('screen')
}, breakPoints)), {}, {
// vars: mergedThemes[selectedTheme],
defaultThemes: themeDefaultTemplate.themes,
userThemes: _objectSpread(_objectSpread({}, variables ? _defineProperty({}, defaultThemeName, variables) : {}), themes),
defaultComponents: themeDefaultTemplate.originalComponents,
userComponents: components,
mixins: (0, _merge["default"])({}, themeDefaultTemplate.defaultMixins, mixins)
});
};
exports.themeBuilder = themeBuilder;
var buildScreen = function buildScreen(_ref24, breakPoints) {
var w = _ref24.window,
s = _ref24.screen;
// This function is responsible for returning
// an object with the following keys fully calculated:
// { window, screen, breakPoints }
var _breakPoints = _slicedToArray(breakPoints, 4),
minPhablet = _breakPoints[0],
minTablet = _breakPoints[1],
minDesktop = _breakPoints[2],
minDesktopHD = _breakPoints[3];
return {
breakPoints: {
phone: w.width >= 0 && w.width < minPhablet,
ltePhablet: w.width < minTablet,
phablet: w.width >= minPhablet && w.width < minTablet,
gtePhablet: w.width >= minPhablet,
lteTablet: w.width < minDesktop,
tablet: w.width >= minTablet && w.width < minDesktop,
gteTablet: w.width >= minTablet,
lteDesktop: w.width < minDesktopHD,
desktop: w.width >= minDesktop && w.width < minDesktopHD,
gteDesktop: w.width >= minDesktop,
desktopHD: w.width >= minDesktopHD
},
window: _objectSpread(_objectSpread({}, w), {}, {
isLandscape: w.width > w.height
}),
screen: _objectSpread(_objectSpread({}, s), {}, {
isLandscape: s.width > s.height
})
};
};
exports.buildScreen = buildScreen;
var NOT_FOUND = '__NOT_FOUND__';
var isValidObj = function isValidObj(o) {
return _typeof(o) === 'object' && Object.keys(o).length > 0;
}; // eslint-disable-next-line no-unused-vars
var mergeObjectsAndFunctions = function mergeObjectsAndFunctions() {
for (var _len = arguments.length, objects = new Array(_len), _key = 0; _key < _len; _key++) {
objects[_key] = arguments[_key];
}
// Remove empty objects
var validObjects = objects.filter(isValidObj);
if (validObjects.length === 0) {
throw new Error('mergeObjectsAndFunctions: We found 0 (zero) valid objects for merging. Please check your theme.');
} else if (validObjects.length === 1) {
// If only 1 obj, return that, no need to merge
return validObjects[0];
} // Lets merge!
var finalObject = _merge["default"].apply(void 0, [{}].concat(_toConsumableArray(validObjects)));
var flatObject = (0, _objFlatten["default"])(finalObject); // only the last object __fun:[functions] are kept after merge
// we need to include functions from all objects
Object.keys(flatObject).forEach(function (key) {
if (key.endsWith(defaultFunctions)) {
// key = 'Button.default.text.__fun'
// value will be an empty [{ }]... lost in flatten
var functionsFromIgnoredObjects = (0, _flatten["default"])(objects.map(function (obj) {
var ignoredFuncArray = (0, _get["default"])(obj, key, NOT_FOUND); // objects[x] has some functions to add?
if (ignoredFuncArray === NOT_FOUND) {
return null;
}
if (!Array.isArray(ignoredFuncArray)) {
throw new Error("mergeObjectsAndFunctions: ".concat(key, " is not an 'array'. Please check your theme."));
}
var notAFunction = ignoredFuncArray.find(function (f) {
return typeof f !== 'function';
}) || null;
if (notAFunction) {
var invalidIndex = ignoredFuncArray.indexOf(notAFunction);
throw new Error("mergeObjectsAndFunctions: ".concat(key, "[").concat(invalidIndex, "] is not a 'function'. Please check your theme."));
}
return ignoredFuncArray;
})); // functionsFromIgnoredObjects = [f1, null, f2, null, f3]
var filteredFunctions = functionsFromIgnoredObjects.filter(function (f) {
return typeof f === 'function';
}); // filteredFunctions = [f1, f2, f3]
if (filteredFunctions.length > 0) {
(0, _set["default"])(finalObject, key, filteredFunctions); // 'Button.default.text.__fun' = [f1, f2, f3] !
}
}
});
return finalObject;
};
var solveThemeFunctions = function solveThemeFunctions(theme, data) {
var dataCopy = (0, _cloneDeep["default"])(data);
var flatObject = (0, _objFlatten["default"])(data);
Object.entries(flatObject).forEach(function (_ref25) {
var _ref26 = _slicedToArray(_ref25, 2),
key = _ref26[0],
value = _ref26[1];
if (key.endsWith(defaultFunctions)) {
// key = 'Button.default.text.__fun'
// value will be an empty [{ }]... lost in flatten
var themeFunctions = (0, _get["default"])(data, key, NOT_FOUND); // themeFunctions is a valid array of functions?
if (themeFunctions === NOT_FOUND) {
throw new Error("solveThemeFunctions: ".concat(key, " is 'null'. Please check your theme."));
}
if (!Array.isArray(themeFunctions)) {
throw new Error("solveThemeFunctions: ".concat(key, " is not an 'array'. Please check your theme."));
}
var functionsResults = themeFunctions.map(function (fun, index) {
if (typeof fun !== 'function') {
throw new Error("solveThemeFunctions: ".concat(key, "[").concat(index, "] is not a 'function'. Please check your theme."));
}
return solveThemeFunctions(theme, fun(theme));
}); // functionsResults = [{...}, null, {...}, null, {...}]
var filteredResults = functionsResults.filter(isValidObj); // filteredResults = [{...}, {...}, {...}]
if (filteredResults.length > 0) {
var mergedResults = _merge["default"].apply(void 0, [{}].concat(_toConsumableArray(filteredResults))); // mergedResults = { ... ... ... }
var targetKeyToApplyResults = key.split('.').splice(0, key.split('.').length - 1).join('.'); // targetKeyToApplyResults = 'Button.default.text'
if (targetKeyToApplyResults) {
var targetKeyValue = (0, _get["default"])(data, targetKeyToApplyResults, {}); // targetKeyValue = { old stuff }
var mergedFunctionResult = (0, _merge["default"])({}, targetKeyValue, mergedResults);
mergedFunctionResult.__fun = null;
(0, _set["default"])(dataCopy, targetKeyToApplyResults, mergedFunctionResult); // 'Button.default.text' = { old stuff, results }
// 'Button.default.text.__fun' = null
} else {
// no key. we are solving for root object
(0, _merge["default"])(dataCopy, mergedResults);
dataCopy.__fun = null; // dataCopy = { old stuff, results }
// dataCopy.__fun = null
}
}
}
});
return dataCopy;
};