UNPKG

tw-merge

Version:

Merge CSS utility classes without style conflicts - small and zero config

80 lines (60 loc) 2.26 kB
import { Handler, RuleSet } from "../rules"; import { createLruCache } from "./create-lru-cache"; import { normalizeContext } from "./utils"; type ParsedRule = [RegExp, Handler]; export type CreateMergeConfig = { cacheSize?: number; separator?: string; prefix?: string; }; export function createMerge( ruleSet: RuleSet, { cacheSize = 500, separator = ":", prefix }: CreateMergeConfig = {} ) { const cache = createLruCache<string, string>(cacheSize); const parsedRuleSet = ruleSet.map( ([regExp, handler]) => [ new RegExp( `^(?<c>.*${separator}!?|!?)?-?${prefix ? `${prefix}-` : ""}${regExp}` ), handler, ] as ParsedRule ); function merge(className: string) { const cached = cache.get(className); if (cached !== undefined) return cached; const memoryStore: Partial<Record<string, unknown>>[] = []; const classes = className.split(" "); const outputClasses: string[] = []; // - for each class from right to left for (let classI = classes.length - 1; classI >= 0; classI--) { const currentClass = classes[classI]!; let didNotMatchOrWasContinued = true; // - for each rule for (let ruleI = 0; ruleI < parsedRuleSet.length; ruleI++) { const rule = parsedRuleSet[ruleI]!; const regexp = rule[0]; const match = currentClass.match(regexp); // - if class matches rule, execute it if (match) { didNotMatchOrWasContinued = false; const groups = match.groups!; const context = normalizeContext(groups?.c ?? "", separator); const handler = rule[1]; const memory = ((memoryStore[ruleI] ??= {})[context] ??= {}); const result = handler(memory, groups!); const keepClass = result === true; const continueToNextRule = result === "c"; if (keepClass) outputClasses.unshift(currentClass); // - finish with the class unless the rule says so if (!continueToNextRule) break; didNotMatchOrWasContinued = true; } } if (didNotMatchOrWasContinued) outputClasses.unshift(currentClass); } return cache.set(className, outputClasses.join(" ")); } return merge; }