UNPKG

tw-merge

Version:

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

360 lines (351 loc) 15.9 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); // LRU cache inspired from hashlru (https://github.com/dominictarr/hashlru/blob/v1.0.4/index.js) but object replaced with Map to improve performance function createLruCache(maxCacheSize) { if (maxCacheSize < 1) return { get: function get() { return undefined; }, set: function set(_, value) { return value; } }; var cacheSize = 0; var cache = new Map(); var previousCache = new Map(); function update(key, value) { cache.set(key, value); cacheSize++; if (cacheSize > maxCacheSize) { cacheSize = 0; previousCache = cache; cache = new Map(); } } return { get: function get(key) { var value = cache.get(key); if (value !== undefined) return value; if ((value = previousCache.get(key)) !== undefined) { update(key, value); return value; } }, set: function set(key, value) { if (cache.has(key)) cache.set(key, value);else update(key, value); return value; } }; } function isNumericValue(value) { var _value$match; if (!value) return true; var arbitraryValue = (_value$match = value.match(/^\[(.*)\]$/)) == null ? void 0 : _value$match[1]; return !isNaN(parseInt(arbitraryValue != null ? arbitraryValue : value)); } function sortContextSection(section, separator) { return section.sort(function (a, b) { if (a.startsWith("[") || b.startsWith("[")) return 0; return a.localeCompare(b); }).join(separator); } function normalizeContext(context, separator) { if (!context) return context; var important = context.endsWith("!"); var variants = context.replace(/:!?$/, "").split(separator); var section = []; var normalizedSections = []; function commitSection() { if (section.length > 0) normalizedSections.push(sortContextSection(section, separator)); } for (var i = 0; i < variants.length; i++) { var variant = variants[i]; if (variant.startsWith("[")) { // is arbitrary variant commitSection(); normalizedSections.push(variant); section = []; } else section.push(variant); } commitSection(); return "" + normalizedSections.join(separator) + separator + (important ? "!" : ""); } function createMerge(ruleSet, _temp) { var _ref = _temp === void 0 ? {} : _temp, _ref$cacheSize = _ref.cacheSize, cacheSize = _ref$cacheSize === void 0 ? 500 : _ref$cacheSize, _ref$separator = _ref.separator, separator = _ref$separator === void 0 ? ":" : _ref$separator, prefix = _ref.prefix; var cache = createLruCache(cacheSize); var parsedRuleSet = ruleSet.map(function (_ref2) { var regExp = _ref2[0], handler = _ref2[1]; return [new RegExp("^(?<c>.*" + separator + "!?|!?)?-?" + (prefix ? prefix + "-" : "") + regExp), handler]; }); function merge(className) { var cached = cache.get(className); if (cached !== undefined) return cached; var memoryStore = []; var classes = className.split(" "); var outputClasses = []; // - for each class from right to left for (var classI = classes.length - 1; classI >= 0; classI--) { var currentClass = classes[classI]; var didNotMatchOrWasContinued = true; // - for each rule for (var ruleI = 0; ruleI < parsedRuleSet.length; ruleI++) { var rule = parsedRuleSet[ruleI]; var regexp = rule[0]; var match = currentClass.match(regexp); // - if class matches rule, execute it if (match) { var _groups$c, _memoryStore$ruleI, _memoryStore$ruleI$co, _ruleI, _memoryStore$_ruleI; didNotMatchOrWasContinued = false; var groups = match.groups; var context = normalizeContext((_groups$c = groups == null ? void 0 : groups.c) != null ? _groups$c : "", separator); var handler = rule[1]; var memory = (_memoryStore$ruleI$co = (_memoryStore$ruleI = (_memoryStore$_ruleI = memoryStore[_ruleI = ruleI]) != null ? _memoryStore$_ruleI : memoryStore[_ruleI] = {})[context]) != null ? _memoryStore$ruleI$co : _memoryStore$ruleI[context] = {}; var result = handler(memory, groups); var keepClass = result === true; var 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; } var TRAILING_SLASH_REGEXP = "(\\/\\d+)?"; var VALUE_REGEXP = "(-(?<v>.+?)" + TRAILING_SLASH_REGEXP + ")?"; function createSimpleHandler(_temp) { var _ref = _temp === void 0 ? {} : _temp, byType = _ref.byType; var simpleHandler = function simpleHandler(memory, _ref2) { var _memory$target; var value = _ref2.v, target = _ref2.t; var type = byType && isNumericValue(value) ? "number" : "other"; var mem = (_memory$target = memory[target]) != null ? _memory$target : memory[target] = {}; // seen before if (mem[type]) return false; // never seen return mem[type] = true; }; return simpleHandler; } function simpleRule(target, _temp2) { var _ref3 = _temp2 === void 0 ? {} : _temp2, byType = _ref3.byType; var regExp = "(?<t>" + target + ")" + VALUE_REGEXP + "$"; return [regExp, createSimpleHandler({ byType: byType })]; } var CARDINAL_OVERRIDES = { t: ",y,tl,tr", r: ",x,tr,br", b: ",y,br,bl", l: ",x,bl,tl", x: "", y: "", s: "", e: "", ss: ",e,s", se: ",e,s", es: ",e,s", ee: ",e,s" }; var CARDINAL_DIRECTIONS = /*#__PURE__*/Object.keys(CARDINAL_OVERRIDES).join("|") + "|tl|tr|br|bl"; function createCardinalHandler(_temp3) { var _ref4 = _temp3 === void 0 ? {} : _temp3, byType = _ref4.byType; var cardinalHandler = function cardinalHandler(memory, _ref5) { var _memory$direction, _memory$_, _memory$_$type, _memory$_2, _CARDINAL_OVERRIDES$d; var value = _ref5.v, _ref5$d = _ref5.d, direction = _ref5$d === void 0 ? "" : _ref5$d; var type = byType && isNumericValue(value) ? "number" : "other"; var mem = (_memory$direction = memory[direction]) != null ? _memory$direction : memory[direction] = {}; // seen before if (mem[type]) return false; // apply override var memOverriders = (_memory$_$type = (_memory$_ = (_memory$_2 = memory._) != null ? _memory$_2 : memory._ = {})[type]) != null ? _memory$_$type : _memory$_[type] = new Set(); if ((_CARDINAL_OVERRIDES$d = CARDINAL_OVERRIDES[direction]) != null && _CARDINAL_OVERRIDES$d.split(",").some(function (dir) { return memOverriders.has(dir); })) return false; // remember overrider memOverriders.add(direction); // never seen mem[type] = true; return true; }; return cardinalHandler; } function cardinalRule(target, _temp4) { var _ref6 = _temp4 === void 0 ? {} : _temp4, _ref6$dash = _ref6.dash, dash = _ref6$dash === void 0 ? true : _ref6$dash, byType = _ref6.byType; var _target = target + "(" + (dash ? "-" : "") + "(?<d>" + CARDINAL_DIRECTIONS + "))?"; var regExp = "" + _target + VALUE_REGEXP + "$"; return [regExp, createCardinalHandler({ byType: byType })]; } function cardinalRules(targets, options) { var _targets = targets.split("|"); return _targets.map(function (target) { return cardinalRule(target, options); }); } // unique rule // ----------- function createUniqueHandler() { var uniqueHandler = function uniqueHandler(memory, groups) { var key = Object.entries(groups).find(function (x) { return x[1]; })[0]; return memory[key] ? false : memory[key] = true; }; return uniqueHandler; } function uniqueRule(targets) { var regExp = "(" + targets.map(function (target, targetI) { return Array.isArray(target) ? target.slice(1).map(function (subtarget, subtargetI) { return "(?<i" + targetI + "_" + subtargetI + ">" + (target[0] + "-(" + subtarget + ")") + ")"; }) : "(?<i" + targetI + ">" + target + ")"; }).flat().join("|") + ")" + TRAILING_SLASH_REGEXP + "$"; return [regExp, createUniqueHandler()]; } // arbitrary rule // -------------- function createArbitraryHandler() { var arbitraryHandler = function arbitraryHandler(memory, _ref7) { var _memory$property; var property = _ref7.p; var mem = (_memory$property = memory[property]) != null ? _memory$property : memory[property] = {}; // seen before if (mem.done) return false; // never seen return mem.done = true; }; return arbitraryHandler; } function arbitraryRule() { return ["\\[(?<p>.+?):.*\\]$", createArbitraryHandler()]; } function createConflictHandler(targets) { var overridableMap = {}; Object.entries(targets).forEach(function (_ref8) { var overridingUtility = _ref8[0], overridableUtilities = _ref8[1]; return overridableUtilities.split("|").forEach(function (value) { var _overridableMap$value; (_overridableMap$value = overridableMap[value]) != null ? _overridableMap$value : overridableMap[value] = []; overridableMap[value].push(overridingUtility); }); }); var conflictHandler = function conflictHandler(memory, _ref9) { var utility = _ref9.u; // is overridable utility and overriding utility has been seen var skipClass = Boolean(utility in overridableMap && overridableMap[utility].some(function (u) { return memory[u]; })); if (skipClass) return false; // is overriding utility if (utility in targets) memory[utility] = true; // continue evaluating other rules return "c"; }; return conflictHandler; } function conflictRule(targets) { var overridingUtilities = Object.keys(targets); var overridableUtilities = Object.values(targets).join("|").split("|"); var matchingClasses = [].concat(overridingUtilities, overridableUtilities); var utility = "(?<u>" + matchingClasses.join("|") + ")"; var regExp = "" + utility + VALUE_REGEXP + "$"; return [regExp, createConflictHandler(targets)]; } var DISPLAY = "block|inline-block|inline-flex|inline-table|inline-grid|inline|flex|table-caption|table-cell|table-column-group|table-column|table-footer-group|table-header-group|table-row-group|table-row|table|flow-root|grid|contents|list-item|hidden"; var ISOLATION = "isolate|isolation-auto"; var OBJECT_FIT = "contain|cover|fill|none|scale-down"; var BG_AND_OBJECT_POSITION = "bottom|center|left|left-bottom|left-top|right|right-bottom|right-top|top"; var POSITION = "static|fixed|absolute|relative|sticky"; var VISIBILITY = "visible|invisible|collapse"; var FLEX_DIRECTION = "row|row-reverse|col|col-reverse"; var FLEX_WRAP = "wrap|wrap-reverse|nowrap"; var ALIGN_CONTENT = "normal|center|start|end|between|around|evenly|baseline|stretch"; var FONT_AND_SHADOW_SIZE = "xs|sm|base|md|lg|xl|[\\d.]+xl|inner|none"; var FONT_SMOOTHING = "antialiased|subpixel-antialiased"; var FONT_STYLE = "italic|not-italic"; var FONT_WEIGHT = "thin|extralight|light|normal|medium|semibold|bold|extrabold|black"; var LIST_STYLE_POSITION = "inside|outside"; var TEXT_ALIGN = "left|center|right|justify|start|end"; var TEXT_DECORATION = "underline|overline|line-through|no-underline"; var TEXT_DECORATION_STYLE = "solid|double|dotted|dashed|wavy"; var TEXT_TRANSFORM = "uppercase|lowercase|capitalize|normal-case"; var TEXT_OVERFLOW = "truncate|text-ellipsis|text-clip"; var BG_ATTACHMENT = "fixed|local|scroll"; var BG_REPEAT = "repeat|no-repeat|repeat-x|repeat-y|repeat-round|repeat-space"; var BG_SIZE = "auto|cover|contain"; var BORDER_AND_OUTLINE_STYLE = "solid|dashed|dotted|double|hidden|none"; var FVN_FIGURE = "lining-nums|oldstyle-nums"; var FVN_SPACING = "proportional-nums|tabular-nums"; var FVN_FRACTION = "diagonal-fractions|stacked-fractions"; var SCROLL_BEHAVIOR = "auto|smooth"; var SCROLL_SNAP_ALIGN = "start|end|center|none"; var SCROLL_SNAP_STOP = "normal|always"; var SCROLL_SNAP_TYPE = "none|x|y|both|mandatory|proximity"; // TODO: text-<something>/20 should override line-height (leading) // TODO: ^ same with opacities and other trailing slash values // TODO: text-decoration-thickness (conflicts with text-decoration-color and there are custom values: auto and from-font) function tailwind() { return [ // these rules are at the top because they need to run before others conflictRule({ "inset-x": "left|right", "inset-y": "top|bottom", inset: "inset-x|inset-y|start|end|left|right|top|bottom", "sr-only": "not-sr-only", "not-sr-only": "sr-only", "normal-nums": "ordinal|slashed-zero|lining-nums|oldstyle-nums|proportional-nums|tabular-nums|diagonal-fractions|stacked-fractons", ordinal: "normal-nums", "slashed-zero": "normal-nums", "lining-nums": "normal-nums", "oldstyle-nums": "normal-nums", "proportional-nums": "normal-nums", "tabular-nums": "normal-nums", "diagonal-fractions": "normal-nums", "stacked-fractons": "normal-nums", "bg-gradient": "bg-none", "bg-none": "bg-gradient" }), uniqueRule([DISPLAY, ISOLATION, POSITION, VISIBILITY, FONT_SMOOTHING, FONT_STYLE, FVN_FIGURE, FVN_SPACING, FVN_FRACTION, TEXT_DECORATION, TEXT_TRANSFORM, TEXT_OVERFLOW]), uniqueRule([["content", ALIGN_CONTENT], ["list", LIST_STYLE_POSITION], ["decoration", TEXT_DECORATION_STYLE], ["border", BORDER_AND_OUTLINE_STYLE], ["divide", BORDER_AND_OUTLINE_STYLE], ["outline|outline", BORDER_AND_OUTLINE_STYLE], ["shadow", FONT_AND_SHADOW_SIZE], ["font", FONT_WEIGHT], ["object", OBJECT_FIT, BG_AND_OBJECT_POSITION]]), uniqueRule([["scroll", SCROLL_BEHAVIOR, SCROLL_SNAP_ALIGN, SCROLL_SNAP_STOP, SCROLL_SNAP_TYPE], ["bg", BG_ATTACHMENT, BG_AND_OBJECT_POSITION, BG_REPEAT, BG_SIZE], ["text", TEXT_ALIGN, FONT_AND_SHADOW_SIZE], ["flex", FLEX_DIRECTION, FLEX_WRAP]]), conflictRule({ flex: "basis|grow|shrink" }), // ----------------------------------------------------------------- simpleRule("accent|align|animate|aspect|auto-cols|auto-rows|backdrop-blur|backdrop-brightness|backdrop-contrast|backdrop-grayscale|backdrop-hue-rotate|backdrop-invert|backdrop-opacity|backdrop-saturate|backdrop-sepia|basis|bg-blend|bg-clip|bg-origin|bg-none|bg-gradient|bg|blur|border-collapse|border-spacing|bottom|box-decoration|box|break-after|break-before|break-inside|break|brightness|caption|caret|clear|col-end|col-start|columns|col|content|contrast|cursor|decoration|delay|divide-x-reverse|divide-x|divide-y-reverse|divide-y|divide|drop-shadow|duration|ease|end|fill|flex|float|grayscale|grid-cols|grid-flow|grid-rows|grow|hue-rotate|hyphens|h|indent|invert|items|justify-items|justify-self|justify|leading|left|line-clamp|list-image|list|max-h|max-w|min-h|min-w|mix-blend|opacity|order|origin|outline-offset|place-content|place-items|place-self|pointer-events|resize|right|ring-inset|rotate|row-end|row-start|row|saturate|select|self|sepia|shadow|shrink|skew-x|skew-y|space-x-reverse|space-x|space-y-reverse|space-y|start|table|top|touch|tracking|transition|translate-x|translate-y|underline-offset|whitespace|will-change|w|z"), simpleRule("text|outline|ring-offset|ring|from|via|to|stroke|font", { byType: true }), cardinalRule("border", { byType: true })].concat(cardinalRules("rounded|gap|inset|scale|overflow|overscroll"), cardinalRules("p|m|scroll-m|scroll-p", { dash: false }), [arbitraryRule()]); } var twMerge = /*#__PURE__*/createMerge( /*#__PURE__*/tailwind()); exports.arbitraryRule = arbitraryRule; exports.cardinalRule = cardinalRule; exports.cardinalRules = cardinalRules; exports.conflictRule = conflictRule; exports.createMerge = createMerge; exports.simpleRule = simpleRule; exports.tailwind = tailwind; exports.twMerge = twMerge; exports.uniqueRule = uniqueRule; //# sourceMappingURL=tw-merge.cjs.development.js.map