"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.styleToClassName = exports.applyRegistration = exports.styleToRegistration = exports.serializeRuleEntries = void 0; var tslib_1 = require("tslib"); var Stylesheet_1 = require("./Stylesheet"); var kebabRules_1 = require("./transforms/kebabRules"); var prefixRules_1 = require("./transforms/prefixRules"); var provideUnits_1 = require("./transforms/provideUnits"); var rtlifyRules_1 = require("./transforms/rtlifyRules"); var tokenizeWithParentheses_1 = require("./tokenizeWithParentheses"); var DISPLAY_NAME = 'displayName'; function getDisplayName(rules) { var rootStyle = rules && rules['&']; return rootStyle ? rootStyle.displayName : undefined; } var globalSelectorRegExp = /\:global\((.+?)\)/g; /** * Finds comma separated selectors in a :global() e.g. ":global(.class1, .class2, .class3)" * and wraps them each in their own global ":global(.class1), :global(.class2), :global(.class3)" * * @param selectorWithGlobals The selector to process * @returns The updated selector */ function expandCommaSeparatedGlobals(selectorWithGlobals) { // We the selector does not have a :global() we can shortcut if (!globalSelectorRegExp.test(selectorWithGlobals)) { return selectorWithGlobals; } var replacementInfo = []; var findGlobal = /\:global\((.+?)\)/g; var match = null; // Create a result list for global selectors so we can replace them. while ((match = findGlobal.exec(selectorWithGlobals))) { // Only if the found selector is a comma separated list we'll process it. if (match[1].indexOf(',') > -1) { replacementInfo.push([ match.index, match.index + match[0].length, // Wrap each of the found selectors in :global() match[1] .split(',') .map(function (v) { return ":global(".concat(v.trim(), ")"); }) .join(', '), ]); } } // Replace the found selectors with their wrapped variants in reverse order return replacementInfo .reverse() .reduce(function (selector, _a) { var matchIndex = _a[0], matchEndIndex = _a[1], replacement = _a[2]; var prefix = selector.slice(0, matchIndex); var suffix = selector.slice(matchEndIndex); return prefix + replacement + suffix; }, selectorWithGlobals); } function isSelector(potentialSelector) { return potentialSelector.indexOf(':global(') >= 0 || potentialSelector.indexOf(':') === 0; } function expandSelector(newSelector, currentSelector) { if (newSelector.indexOf(':global(') >= 0) { return newSelector.replace(globalSelectorRegExp, '$1'); } else if (newSelector.indexOf(':host(') === 0) { return newSelector; } else if (newSelector.indexOf(':') === 0) { return currentSelector + newSelector; } else if (newSelector.indexOf('&') < 0) { return currentSelector + ' ' + newSelector; } return newSelector; } function extractSelector(currentSelector, rules, selector, value, stylesheet) { if (rules === void 0) { rules = { __order: [] }; } if (selector.indexOf('@') === 0) { selector = selector + '{' + currentSelector; extractRules([value], rules, selector, stylesheet); } else if (selector.indexOf(',') > -1) { expandCommaSeparatedGlobals(selector) .split(',') .map(function (s) { return s.trim(); }) .forEach(function (separatedSelector) { return extractRules([value], rules, expandSelector(separatedSelector, currentSelector), stylesheet); }); } else { extractRules([value], rules, expandSelector(selector, currentSelector), stylesheet); } } function extractRules(args, rules, currentSelector, stylesheet) { if (rules === void 0) { rules = { __order: [] }; } if (currentSelector === void 0) { currentSelector = '&'; } var currentRules = rules[currentSelector]; if (!currentRules) { currentRules = {}; rules[currentSelector] = currentRules; rules.__order.push(currentSelector); } for (var _i = 0, args_1 = args; _i < args_1.length; _i++) { var arg = args_1[_i]; // If the arg is a string, we need to look up the class map and merge. if (typeof arg === 'string') { var expandedRules = stylesheet.argsFromClassName(arg); if (expandedRules) { extractRules(expandedRules, rules, currentSelector, stylesheet); } // Else if the arg is an array, we need to recurse in. } else if (Array.isArray(arg)) { extractRules(arg, rules, currentSelector, stylesheet); } else { for (var prop in arg) { if (arg.hasOwnProperty(prop)) { var propValue = arg[prop]; if (prop === 'selectors') { // every child is a selector. var selectors = arg.selectors; for (var newSelector in selectors) { if (selectors.hasOwnProperty(newSelector)) { extractSelector(currentSelector, rules, newSelector, selectors[newSelector], stylesheet); } } } else if (typeof propValue === 'object' || isSelector(prop)) { // prop is a selector. if (propValue !== null && propValue !== undefined) { extractSelector(currentSelector, rules, prop, propValue, stylesheet); } } else { if (propValue !== undefined) { // Else, add the rule to the currentSelector. if (prop === 'margin' || prop === 'padding') { expandQuads(currentRules, prop, propValue); } else { currentRules[prop] = propValue; } } } } } } } return rules; } function expandQuads(currentRules, name, value) { var parts = typeof value === 'string' ? (0, tokenizeWithParentheses_1.tokenizeWithParentheses)(value) : [value]; if (parts.length === 0) { parts.push(value); } if (parts[parts.length - 1] === '!important') { // Remove !important from parts, and append it to each part individually parts = parts.slice(0, -1).map(function (p) { return p + ' !important'; }); } currentRules[name + 'Top'] = parts[0]; currentRules[name + 'Right'] = parts[1] || parts[0]; currentRules[name + 'Bottom'] = parts[2] || parts[0]; currentRules[name + 'Left'] = parts[3] || parts[1] || parts[0]; } function getKeyForRules(options, rules) { var serialized = [options.rtl ? 'rtl' : 'ltr']; var hasProps = false; for (var _i = 0, _a = rules.__order; _i < _a.length; _i++) { var selector = _a[_i]; serialized.push(selector); var rulesForSelector = rules[selector]; for (var propName in rulesForSelector) { if (rulesForSelector.hasOwnProperty(propName) && rulesForSelector[propName] !== undefined) { hasProps = true; serialized.push(propName, rulesForSelector[propName]); } } } return hasProps ? serialized.join('') : undefined; } function repeatString(target, count) { if (count <= 0) { return ''; } if (count === 1) { return target; } return target + repeatString(target, count - 1); } function serializeRuleEntries(options, ruleEntries) { if (!ruleEntries) { return ''; } var allEntries = []; for (var entry in ruleEntries) { if (ruleEntries.hasOwnProperty(entry) && entry !== DISPLAY_NAME && ruleEntries[entry] !== undefined) { allEntries.push(entry, ruleEntries[entry]); } } // Apply transforms. for (var i = 0; i < allEntries.length; i += 2) { (0, kebabRules_1.kebabRules)(allEntries, i); (0, provideUnits_1.provideUnits)(allEntries, i); (0, rtlifyRules_1.rtlifyRules)(options, allEntries, i); (0, prefixRules_1.prefixRules)(allEntries, i); } // Apply punctuation. for (var i = 1; i < allEntries.length; i += 4) { allEntries.splice(i, 1, ':', allEntries[i], ';'); } return allEntries.join(''); } exports.serializeRuleEntries = serializeRuleEntries; function styleToRegistration(options) { var _a; var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } var stylesheet = (_a = options.stylesheet) !== null && _a !== void 0 ? _a : Stylesheet_1.Stylesheet.getInstance(options.shadowConfig); var rules = extractRules(args, undefined, undefined, stylesheet); var key = getKeyForRules(options, rules); if (key) { var registration = { className: stylesheet.classNameFromKey(key), key: key, args: args, }; if (!registration.className) { registration.className = stylesheet.getClassName(getDisplayName(rules)); var rulesToInsert = []; for (var _b = 0, _c = rules.__order; _b < _c.length; _b++) { var selector = _c[_b]; rulesToInsert.push(selector, serializeRuleEntries(options, rules[selector])); } registration.rulesToInsert = rulesToInsert; } return registration; } return undefined; } exports.styleToRegistration = styleToRegistration; /** * Insert style to stylesheet. * @param registration Style registration. * @param specificityMultiplier Number of times classname selector is repeated in the css rule. * This is to increase css specificity in case it's needed. Default to 1. */ function applyRegistration(registration, specificityMultiplier, shadowConfig, sheet) { if (specificityMultiplier === void 0) { specificityMultiplier = 1; } var stylesheet = sheet !== null && sheet !== void 0 ? sheet : Stylesheet_1.Stylesheet.getInstance(shadowConfig); var className = registration.className, key = registration.key, args = registration.args, rulesToInsert = registration.rulesToInsert; if (rulesToInsert) { // rulesToInsert is an ordered array of selector/rule pairs. for (var i = 0; i < rulesToInsert.length; i += 2) { var rules = rulesToInsert[i + 1]; if (rules) { var selector = rulesToInsert[i]; selector = selector.replace(/&/g, repeatString(".".concat(registration.className), specificityMultiplier)); // Insert. Note if a media query, we must close the query with a final bracket. var processedRule = "".concat(selector, "{").concat(rules, "}").concat(selector.indexOf('@') === 0 ? '}' : ''); stylesheet.insertRule(processedRule); } } stylesheet.cacheClassName(className, key, args, rulesToInsert); } } exports.applyRegistration = applyRegistration; function styleToClassName(options) { var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } var registration = styleToRegistration.apply(void 0, tslib_1.__spreadArray([options], args, false)); if (registration) { applyRegistration(registration, options.specificityMultiplier, options.shadowConfig, options.stylesheet); return registration.className; } return ''; } exports.styleToClassName = styleToClassName; //# sourceMappingURL=styleToClassName.js.map