105 lines
5.3 KiB
JavaScript
105 lines
5.3 KiB
JavaScript
'use strict';
|
|
|
|
var constants = require('./constants.cjs.js');
|
|
var hashSequence = require('./runtime/utils/hashSequence.cjs.js');
|
|
var reduceToClassNameForSlots = require('./runtime/reduceToClassNameForSlots.cjs.js');
|
|
|
|
// Contains a mapping of previously resolved sequences of atomic classnames
|
|
const mergeClassesCachedResults = {};
|
|
function mergeClasses() {
|
|
// arguments are parsed manually to avoid double loops as TS & Babel transforms rest via an additional loop
|
|
// @see https://babeljs.io/docs/en/babel-plugin-transform-parameters
|
|
/* eslint-disable prefer-rest-params */
|
|
let dir = null;
|
|
let resultClassName = '';
|
|
// Is used as a cache key to avoid object merging
|
|
let sequenceMatch = '';
|
|
const sequencesIds = new Array(arguments.length);
|
|
let containsResetClassName = '';
|
|
for (let i = 0; i < arguments.length; i++) {
|
|
const className = arguments[i];
|
|
if (typeof className === 'string' && className !== '') {
|
|
// All classes generated by `makeStyles()` are prefixed by a sequence hash, this allows to identify class sets
|
|
// without parsing each className in a string
|
|
const sequenceIndex = className.indexOf(constants.SEQUENCE_PREFIX);
|
|
if (sequenceIndex === -1) {
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
className.split(' ').forEach(entry => {
|
|
if (entry.startsWith(constants.RESET_HASH_PREFIX) && constants.DEBUG_RESET_CLASSES[entry]) {
|
|
if (containsResetClassName) {
|
|
// eslint-disable-next-line no-console
|
|
console.error('mergeClasses(): a passed string contains multiple classes produced by makeResetStyles (' + `${className} & ${resultClassName}, this will lead to non-deterministic behavior. Learn more:` + 'https://griffel.js.org/react/api/make-reset-styles#limitations' + '\n' + `Source string: ${className}`);
|
|
} else {
|
|
containsResetClassName = entry;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
resultClassName += className + ' ';
|
|
} else {
|
|
const sequenceId = className.substr(sequenceIndex, constants.SEQUENCE_SIZE);
|
|
// Handles a case with mixed classnames, i.e. "ui-button ATOMIC_CLASSES"
|
|
if (sequenceIndex > 0) {
|
|
resultClassName += className.slice(0, sequenceIndex);
|
|
}
|
|
sequenceMatch += sequenceId;
|
|
sequencesIds[i] = sequenceId;
|
|
}
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
if (className.indexOf(constants.SEQUENCE_PREFIX, sequenceIndex + 1) !== -1) {
|
|
// eslint-disable-next-line no-console
|
|
console.error('mergeClasses(): a passed string contains multiple identifiers of atomic classes (classes that start ' + `with "${constants.SEQUENCE_PREFIX}"), it's possible that passed classes were concatenated in a wrong way. ` + `Source string: ${className}`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// .slice() there allows to avoid trailing space for non-atomic classes
|
|
// "ui-button ui-flex " => "ui-button ui-flex"
|
|
if (sequenceMatch === '') {
|
|
return resultClassName.slice(0, -1);
|
|
}
|
|
// It's safe to reuse results to avoid continuous merging as results are stable
|
|
// "__seq1 ... __seq2 ..." => "__seq12 ..."
|
|
const mergeClassesResult = mergeClassesCachedResults[sequenceMatch];
|
|
if (mergeClassesResult !== undefined) {
|
|
return resultClassName + mergeClassesResult;
|
|
}
|
|
const sequenceMappings = [];
|
|
for (let i = 0; i < arguments.length; i++) {
|
|
const sequenceId = sequencesIds[i];
|
|
if (sequenceId) {
|
|
const sequenceMapping = constants.DEFINITION_LOOKUP_TABLE[sequenceId];
|
|
if (sequenceMapping) {
|
|
sequenceMappings.push(sequenceMapping[constants.LOOKUP_DEFINITIONS_INDEX]);
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
if (dir !== null && dir !== sequenceMapping[constants.LOOKUP_DIR_INDEX]) {
|
|
// eslint-disable-next-line no-console
|
|
console.error(`mergeClasses(): a passed string contains an identifier (${sequenceId}) that has different direction ` + `(dir="${sequenceMapping[1] ? 'rtl' : 'ltr'}") setting than other classes. This is not supported. ` + `Source string: ${arguments[i]}`);
|
|
}
|
|
}
|
|
dir = sequenceMapping[constants.LOOKUP_DIR_INDEX];
|
|
} else {
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
// eslint-disable-next-line no-console
|
|
console.error(`mergeClasses(): a passed string contains an identifier (${sequenceId}) that does not match any entry ` + `in cache. Source string: ${arguments[i]}`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// eslint-disable-next-line prefer-spread
|
|
const resultClassesMap = Object.assign.apply(Object,
|
|
// .assign() mutates the first object, we can't mutate mappings as it will produce invalid results later
|
|
[{}].concat(sequenceMappings));
|
|
const [atomicClasses, classesMapHash] = reduceToClassNameForSlots.reduceToClassName(resultClassesMap, dir);
|
|
// Each merge of classes generates a new sequence of atomic classes that needs to be registered
|
|
const newSequenceHash = hashSequence.hashSequence(classesMapHash, dir, sequencesIds);
|
|
const newClassName = newSequenceHash + ' ' + atomicClasses;
|
|
mergeClassesCachedResults[sequenceMatch] = newClassName;
|
|
constants.DEFINITION_LOOKUP_TABLE[newSequenceHash] = [resultClassesMap, dir];
|
|
return resultClassName + newClassName;
|
|
}
|
|
|
|
exports.mergeClasses = mergeClasses;
|
|
exports.mergeClassesCachedResults = mergeClassesCachedResults;
|
|
//# sourceMappingURL=mergeClasses.cjs.js.map
|