UNPKG

tailwind-merge

Version:

Merge Tailwind CSS classes without style conflicts

116 lines (93 loc) 3.72 kB
import { ConfigUtils } from './config-utils' import { IMPORTANT_MODIFIER } from './parse-class-name' const SPLIT_CLASSES_REGEX = /\s+/ export const mergeClassList = (classList: string, configUtils: ConfigUtils) => { const { parseClassName, getClassGroupId, getConflictingClassGroupIds, sortModifiers, postfixLookupClassGroupIds, } = configUtils /** * Set of classGroupIds in following format: * `{importantModifier}{variantModifiers}{classGroupId}` * @example 'float' * @example 'hover:focus:bg-color' * @example 'md:!pr' */ const classGroupsInConflict: string[] = [] const classNames = classList.trim().split(SPLIT_CLASSES_REGEX) let result = '' for (let index = classNames.length - 1; index >= 0; index -= 1) { const originalClassName = classNames[index]! const { isExternal, modifiers, hasImportantModifier, baseClassName, maybePostfixModifierPosition, } = parseClassName(originalClassName) if (isExternal) { result = originalClassName + (result.length > 0 ? ' ' + result : result) continue } let hasPostfixModifier = !!maybePostfixModifierPosition let classGroupId: ReturnType<typeof getClassGroupId> if (hasPostfixModifier) { const baseClassNameWithoutPostfix = baseClassName.substring( 0, maybePostfixModifierPosition, ) classGroupId = getClassGroupId(baseClassNameWithoutPostfix) const classGroupIdWithPostfix = classGroupId && postfixLookupClassGroupIds[classGroupId] ? getClassGroupId(baseClassName) : undefined if (classGroupIdWithPostfix && classGroupIdWithPostfix !== classGroupId) { classGroupId = classGroupIdWithPostfix hasPostfixModifier = false } } else { classGroupId = getClassGroupId(baseClassName) } if (!classGroupId) { if (!hasPostfixModifier) { // Not a Tailwind class result = originalClassName + (result.length > 0 ? ' ' + result : result) continue } classGroupId = getClassGroupId(baseClassName) if (!classGroupId) { // Not a Tailwind class result = originalClassName + (result.length > 0 ? ' ' + result : result) continue } hasPostfixModifier = false } // Fast path: skip sorting for empty or single modifier const variantModifier = modifiers.length === 0 ? '' : modifiers.length === 1 ? modifiers[0]! : sortModifiers(modifiers).join(':') const modifierId = hasImportantModifier ? variantModifier + IMPORTANT_MODIFIER : variantModifier const classId = modifierId + classGroupId if (classGroupsInConflict.indexOf(classId) > -1) { // Tailwind class omitted due to conflict continue } classGroupsInConflict.push(classId) const conflictGroups = getConflictingClassGroupIds(classGroupId, hasPostfixModifier) for (let i = 0; i < conflictGroups.length; ++i) { const group = conflictGroups[i]! classGroupsInConflict.push(modifierId + group) } // Tailwind class not in conflict result = originalClassName + (result.length > 0 ? ' ' + result : result) } return result }