diff --git a/src/lib/merge-classlist.ts b/src/lib/merge-classlist.ts index a41734b..099f9e9 100644 --- a/src/lib/merge-classlist.ts +++ b/src/lib/merge-classlist.ts @@ -1,8 +1,6 @@ import { ConfigUtils } from './config-utils' import { IMPORTANT_MODIFIER, sortModifiers } from './parse-class-name' -const SPLIT_CLASSES_REGEX = /\s+/ - export const mergeClassList = (classList: string, configUtils: ConfigUtils) => { const { parseClassName, getClassGroupId, getConflictingClassGroupIds } = configUtils @@ -13,86 +11,66 @@ export const mergeClassList = (classList: string, configUtils: ConfigUtils) => { * @example 'hover:focus:bg-color' * @example 'md:!pr' */ - const classGroupsInConflict = new Set() - - return ( - classList - .trim() - .split(SPLIT_CLASSES_REGEX) - .map((originalClassName) => { - const { - modifiers, - hasImportantModifier, - baseClassName, - maybePostfixModifierPosition, - } = parseClassName(originalClassName) - - let hasPostfixModifier = Boolean(maybePostfixModifierPosition) - let classGroupId = getClassGroupId( - hasPostfixModifier - ? baseClassName.substring(0, maybePostfixModifierPosition) - : baseClassName, - ) - - if (!classGroupId) { - if (!hasPostfixModifier) { - return { - isTailwindClass: false as const, - originalClassName, - } - } - - classGroupId = getClassGroupId(baseClassName) - - if (!classGroupId) { - return { - isTailwindClass: false as const, - originalClassName, - } - } - - hasPostfixModifier = false - } - - const variantModifier = sortModifiers(modifiers).join(':') - - const modifierId = hasImportantModifier - ? variantModifier + IMPORTANT_MODIFIER - : variantModifier - - return { - isTailwindClass: true as const, - modifierId, - classGroupId, - originalClassName, - hasPostfixModifier, - } - }) - .reverse() - // Last class in conflict wins, so we need to filter conflicting classes in reverse order. - .filter((parsed) => { - if (!parsed.isTailwindClass) { - return true - } - - const { modifierId, classGroupId, hasPostfixModifier } = parsed - - const classId = modifierId + classGroupId - - if (classGroupsInConflict.has(classId)) { - return false - } - - classGroupsInConflict.add(classId) - - getConflictingClassGroupIds(classGroupId, hasPostfixModifier).forEach((group) => - classGroupsInConflict.add(modifierId + group), - ) - - return true - }) - .reverse() - .map((parsed) => parsed.originalClassName) - .join(' ') - ) + const classGroupsInConflict: string[] = [] + + let result = '' + + for (let i = classList.length - 1; i >= 0; ) { + while (classList[i] === ' ') { + --i + } + const nextI = classList.lastIndexOf(' ', i) + const originalClassName = classList.slice(nextI === -1 ? 0 : nextI + 1, i + 1) + i = nextI + + const { modifiers, hasImportantModifier, baseClassName, maybePostfixModifierPosition } = + parseClassName(originalClassName) + + let hasPostfixModifier = Boolean(maybePostfixModifierPosition) + let classGroupId = getClassGroupId( + hasPostfixModifier + ? baseClassName.substring(0, maybePostfixModifierPosition) + : baseClassName, + ) + + if (!classGroupId) { + if (!hasPostfixModifier) { + result = originalClassName + (result.length > 0 ? ' ' + result : result) + continue + } + + classGroupId = getClassGroupId(baseClassName) + + if (!classGroupId) { + result = originalClassName + (result.length > 0 ? ' ' + result : result) + continue + } + + hasPostfixModifier = false + } + + const variantModifier = sortModifiers(modifiers).join(':') + + const modifierId = hasImportantModifier + ? variantModifier + IMPORTANT_MODIFIER + : variantModifier + + const classId = modifierId + classGroupId + + if (classGroupsInConflict.includes(classId)) { + 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) + } + + result = originalClassName + (result.length > 0 ? ' ' + result : result) + } + + return result }