UNPKG

@uifabric/merge-styles

Version:
261 lines 10.5 kB
import { __spreadArrays } from "tslib"; import { Stylesheet } from './Stylesheet'; import { kebabRules } from './transforms/kebabRules'; import { prefixRules } from './transforms/prefixRules'; import { provideUnits } from './transforms/provideUnits'; import { rtlifyRules } from './transforms/rtlifyRules'; 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(" + 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 expandSelector(newSelector, currentSelector) { if (newSelector.indexOf(':global(') >= 0) { return newSelector.replace(globalSelectorRegExp, '$1'); } else if (newSelector.indexOf(':') === 0) { return currentSelector + newSelector; } else if (newSelector.indexOf('&') < 0) { return currentSelector + ' ' + newSelector; } return newSelector; } function extractSelector(currentSelector, rules, selector, value) { if (rules === void 0) { rules = { __order: [] }; } if (selector.indexOf('@') === 0) { selector = selector + '{' + currentSelector; extractRules([value], rules, selector); } else if (selector.indexOf(',') > -1) { expandCommaSeparatedGlobals(selector) .split(',') .map(function (s) { return s.trim(); }) .forEach(function (separatedSelector) { return extractRules([value], rules, expandSelector(separatedSelector, currentSelector)); }); } else { extractRules([value], rules, expandSelector(selector, currentSelector)); } } function extractRules(args, rules, currentSelector) { if (rules === void 0) { rules = { __order: [] }; } if (currentSelector === void 0) { currentSelector = '&'; } var stylesheet = Stylesheet.getInstance(); 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); } // Else if the arg is an array, we need to recurse in. } else if (Array.isArray(arg)) { extractRules(arg, rules, currentSelector); } 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]); } } } else if (typeof propValue === 'object') { // prop is a selector. if (propValue !== null) { extractSelector(currentSelector, rules, prop, propValue); } } 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' ? value.split(' ') : [value]; 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); } export 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) { kebabRules(allEntries, i); provideUnits(allEntries, i); rtlifyRules(options, allEntries, i); prefixRules(allEntries, i); } // Apply punctuation. for (var i = 1; i < allEntries.length; i += 4) { allEntries.splice(i, 1, ':', allEntries[i], ';'); } return allEntries.join(''); } export function styleToRegistration(options) { var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } var rules = extractRules(args); var key = getKeyForRules(options, rules); if (key) { var stylesheet = Stylesheet.getInstance(); var registration = { className: stylesheet.classNameFromKey(key), key: key, args: args, }; if (!registration.className) { registration.className = stylesheet.getClassName(getDisplayName(rules)); var rulesToInsert = []; for (var _a = 0, _b = rules.__order; _a < _b.length; _a++) { var selector = _b[_a]; rulesToInsert.push(selector, serializeRuleEntries(options, rules[selector])); } registration.rulesToInsert = rulesToInsert; } return registration; } return undefined; } /** * 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. */ export function applyRegistration(registration, specificityMultiplier) { if (specificityMultiplier === void 0) { specificityMultiplier = 1; } var stylesheet = Stylesheet.getInstance(); 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("." + registration.className, specificityMultiplier)); // Insert. Note if a media query, we must close the query with a final bracket. var processedRule = selector + "{" + rules + "}" + (selector.indexOf('@') === 0 ? '}' : ''); stylesheet.insertRule(processedRule); } } stylesheet.cacheClassName(className, key, args, rulesToInsert); } } export function styleToClassName(options) { var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } var registration = styleToRegistration.apply(void 0, __spreadArrays([options], args)); if (registration) { applyRegistration(registration, options.specificityMultiplier); return registration.className; } return ''; } //# sourceMappingURL=styleToClassName.js.map