UNPKG

10.5 kBJavaScriptView Raw
1import { __spreadArrays } from "tslib";
2import { Stylesheet } from './Stylesheet';
3import { kebabRules } from './transforms/kebabRules';
4import { prefixRules } from './transforms/prefixRules';
5import { provideUnits } from './transforms/provideUnits';
6import { rtlifyRules } from './transforms/rtlifyRules';
7var DISPLAY_NAME = 'displayName';
8function getDisplayName(rules) {
9 var rootStyle = rules && rules['&'];
10 return rootStyle ? rootStyle.displayName : undefined;
11}
12var globalSelectorRegExp = /\:global\((.+?)\)/g;
13/**
14 * Finds comma separated selectors in a :global() e.g. ":global(.class1, .class2, .class3)"
15 * and wraps them each in their own global ":global(.class1), :global(.class2), :global(.class3)"
16 *
17 * @param selectorWithGlobals The selector to process
18 * @returns The updated selector
19 */
20function expandCommaSeparatedGlobals(selectorWithGlobals) {
21 // We the selector does not have a :global() we can shortcut
22 if (!globalSelectorRegExp.test(selectorWithGlobals)) {
23 return selectorWithGlobals;
24 }
25 var replacementInfo = [];
26 var findGlobal = /\:global\((.+?)\)/g;
27 var match = null;
28 // Create a result list for global selectors so we can replace them.
29 while ((match = findGlobal.exec(selectorWithGlobals))) {
30 // Only if the found selector is a comma separated list we'll process it.
31 if (match[1].indexOf(',') > -1) {
32 replacementInfo.push([
33 match.index,
34 match.index + match[0].length,
35 // Wrap each of the found selectors in :global()
36 match[1]
37 .split(',')
38 .map(function (v) { return ":global(" + v.trim() + ")"; })
39 .join(', '),
40 ]);
41 }
42 }
43 // Replace the found selectors with their wrapped variants in reverse order
44 return replacementInfo
45 .reverse()
46 .reduce(function (selector, _a) {
47 var matchIndex = _a[0], matchEndIndex = _a[1], replacement = _a[2];
48 var prefix = selector.slice(0, matchIndex);
49 var suffix = selector.slice(matchEndIndex);
50 return prefix + replacement + suffix;
51 }, selectorWithGlobals);
52}
53function expandSelector(newSelector, currentSelector) {
54 if (newSelector.indexOf(':global(') >= 0) {
55 return newSelector.replace(globalSelectorRegExp, '$1');
56 }
57 else if (newSelector.indexOf(':') === 0) {
58 return currentSelector + newSelector;
59 }
60 else if (newSelector.indexOf('&') < 0) {
61 return currentSelector + ' ' + newSelector;
62 }
63 return newSelector;
64}
65function extractSelector(currentSelector, rules, selector, value) {
66 if (rules === void 0) { rules = { __order: [] }; }
67 if (selector.indexOf('@') === 0) {
68 selector = selector + '{' + currentSelector;
69 extractRules([value], rules, selector);
70 }
71 else if (selector.indexOf(',') > -1) {
72 expandCommaSeparatedGlobals(selector)
73 .split(',')
74 .map(function (s) { return s.trim(); })
75 .forEach(function (separatedSelector) {
76 return extractRules([value], rules, expandSelector(separatedSelector, currentSelector));
77 });
78 }
79 else {
80 extractRules([value], rules, expandSelector(selector, currentSelector));
81 }
82}
83function extractRules(args, rules, currentSelector) {
84 if (rules === void 0) { rules = { __order: [] }; }
85 if (currentSelector === void 0) { currentSelector = '&'; }
86 var stylesheet = Stylesheet.getInstance();
87 var currentRules = rules[currentSelector];
88 if (!currentRules) {
89 currentRules = {};
90 rules[currentSelector] = currentRules;
91 rules.__order.push(currentSelector);
92 }
93 for (var _i = 0, args_1 = args; _i < args_1.length; _i++) {
94 var arg = args_1[_i];
95 // If the arg is a string, we need to look up the class map and merge.
96 if (typeof arg === 'string') {
97 var expandedRules = stylesheet.argsFromClassName(arg);
98 if (expandedRules) {
99 extractRules(expandedRules, rules, currentSelector);
100 }
101 // Else if the arg is an array, we need to recurse in.
102 }
103 else if (Array.isArray(arg)) {
104 extractRules(arg, rules, currentSelector);
105 }
106 else {
107 for (var prop in arg) {
108 if (arg.hasOwnProperty(prop)) {
109 var propValue = arg[prop];
110 if (prop === 'selectors') {
111 // every child is a selector.
112 var selectors = arg.selectors;
113 for (var newSelector in selectors) {
114 if (selectors.hasOwnProperty(newSelector)) {
115 extractSelector(currentSelector, rules, newSelector, selectors[newSelector]);
116 }
117 }
118 }
119 else if (typeof propValue === 'object') {
120 // prop is a selector.
121 if (propValue !== null) {
122 extractSelector(currentSelector, rules, prop, propValue);
123 }
124 }
125 else {
126 if (propValue !== undefined) {
127 // Else, add the rule to the currentSelector.
128 if (prop === 'margin' || prop === 'padding') {
129 expandQuads(currentRules, prop, propValue);
130 }
131 else {
132 currentRules[prop] = propValue;
133 }
134 }
135 }
136 }
137 }
138 }
139 }
140 return rules;
141}
142function expandQuads(currentRules, name, value) {
143 var parts = typeof value === 'string' ? value.split(' ') : [value];
144 currentRules[name + 'Top'] = parts[0];
145 currentRules[name + 'Right'] = parts[1] || parts[0];
146 currentRules[name + 'Bottom'] = parts[2] || parts[0];
147 currentRules[name + 'Left'] = parts[3] || parts[1] || parts[0];
148}
149function getKeyForRules(options, rules) {
150 var serialized = [options.rtl ? 'rtl' : 'ltr'];
151 var hasProps = false;
152 for (var _i = 0, _a = rules.__order; _i < _a.length; _i++) {
153 var selector = _a[_i];
154 serialized.push(selector);
155 var rulesForSelector = rules[selector];
156 for (var propName in rulesForSelector) {
157 if (rulesForSelector.hasOwnProperty(propName) && rulesForSelector[propName] !== undefined) {
158 hasProps = true;
159 serialized.push(propName, rulesForSelector[propName]);
160 }
161 }
162 }
163 return hasProps ? serialized.join('') : undefined;
164}
165function repeatString(target, count) {
166 if (count <= 0) {
167 return '';
168 }
169 if (count === 1) {
170 return target;
171 }
172 return target + repeatString(target, count - 1);
173}
174export function serializeRuleEntries(options, ruleEntries) {
175 if (!ruleEntries) {
176 return '';
177 }
178 var allEntries = [];
179 for (var entry in ruleEntries) {
180 if (ruleEntries.hasOwnProperty(entry) && entry !== DISPLAY_NAME && ruleEntries[entry] !== undefined) {
181 allEntries.push(entry, ruleEntries[entry]);
182 }
183 }
184 // Apply transforms.
185 for (var i = 0; i < allEntries.length; i += 2) {
186 kebabRules(allEntries, i);
187 provideUnits(allEntries, i);
188 rtlifyRules(options, allEntries, i);
189 prefixRules(allEntries, i);
190 }
191 // Apply punctuation.
192 for (var i = 1; i < allEntries.length; i += 4) {
193 allEntries.splice(i, 1, ':', allEntries[i], ';');
194 }
195 return allEntries.join('');
196}
197export function styleToRegistration(options) {
198 var args = [];
199 for (var _i = 1; _i < arguments.length; _i++) {
200 args[_i - 1] = arguments[_i];
201 }
202 var rules = extractRules(args);
203 var key = getKeyForRules(options, rules);
204 if (key) {
205 var stylesheet = Stylesheet.getInstance();
206 var registration = {
207 className: stylesheet.classNameFromKey(key),
208 key: key,
209 args: args,
210 };
211 if (!registration.className) {
212 registration.className = stylesheet.getClassName(getDisplayName(rules));
213 var rulesToInsert = [];
214 for (var _a = 0, _b = rules.__order; _a < _b.length; _a++) {
215 var selector = _b[_a];
216 rulesToInsert.push(selector, serializeRuleEntries(options, rules[selector]));
217 }
218 registration.rulesToInsert = rulesToInsert;
219 }
220 return registration;
221 }
222 return undefined;
223}
224/**
225 * Insert style to stylesheet.
226 * @param registration Style registration.
227 * @param specificityMultiplier Number of times classname selector is repeated in the css rule.
228 * This is to increase css specificity in case it's needed. Default to 1.
229 */
230export function applyRegistration(registration, specificityMultiplier) {
231 if (specificityMultiplier === void 0) { specificityMultiplier = 1; }
232 var stylesheet = Stylesheet.getInstance();
233 var className = registration.className, key = registration.key, args = registration.args, rulesToInsert = registration.rulesToInsert;
234 if (rulesToInsert) {
235 // rulesToInsert is an ordered array of selector/rule pairs.
236 for (var i = 0; i < rulesToInsert.length; i += 2) {
237 var rules = rulesToInsert[i + 1];
238 if (rules) {
239 var selector = rulesToInsert[i];
240 selector = selector.replace(/&/g, repeatString("." + registration.className, specificityMultiplier));
241 // Insert. Note if a media query, we must close the query with a final bracket.
242 var processedRule = selector + "{" + rules + "}" + (selector.indexOf('@') === 0 ? '}' : '');
243 stylesheet.insertRule(processedRule);
244 }
245 }
246 stylesheet.cacheClassName(className, key, args, rulesToInsert);
247 }
248}
249export function styleToClassName(options) {
250 var args = [];
251 for (var _i = 1; _i < arguments.length; _i++) {
252 args[_i - 1] = arguments[_i];
253 }
254 var registration = styleToRegistration.apply(void 0, __spreadArrays([options], args));
255 if (registration) {
256 applyRegistration(registration, options.specificityMultiplier);
257 return registration.className;
258 }
259 return '';
260}
261//# sourceMappingURL=styleToClassName.js.map
\No newline at end of file