UNPKG

@weareredlight/components

Version:
453 lines (367 loc) 19.8 kB
"use strict"; 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; };