denwa-web-shared
Version:
A shared library for Next.js App Router projects containing reusable components, hooks, schemas, and utilities.
1,556 lines • 217 kB
JavaScript
import { jsxs, jsx } from "react/jsx-runtime";
const TIME = {
seconds: {
minutes10: 600
},
milliseconds: {
milliseconds100: 100,
milliseconds200: 200,
milliseconds500: 500,
seconds1: 1e3,
seconds2: 2e3,
seconds5: 5e3,
minutes1: 6e4
}
};
const THEME = {
VIEW_PORT: {
EXTRA_SMALL: 280,
SMALL: 320,
SMALL_MOBILE: 380,
MOBILE: 450,
MEDIUM: 500,
EXTRA_MEDIUM: 600,
TABLET: 768,
LAPTOP: 1024,
LAPTOP_BIG: 1200,
BIG: 1440,
VERY_BIG: 1920
},
OFFSET: {
1: 8,
2: 16,
3: 24,
4: 32,
5: 40,
6: 48,
7: 56,
8: 64
}
};
const CITY_MASK = {
CITY: "{{CITY}}",
CITY_DECL: "{{CITY_DECL}}",
CITY_REGION: "{{CITY_REGION}}",
CITY_REGION_DECL: "{{CITY_REGION_DECL}}"
};
const getImageData = (basePath, filename, ext) => ({
image1x: `${basePath}/${filename}.${ext}`,
image2x: `${basePath}/${filename}_2x.${ext}`,
image1xWebp: `${basePath}/${filename}.webp`,
image2xWebp: `${basePath}/${filename}_2x.webp`,
image1xAvif: `${basePath}/${filename}.avif`,
image2xAvif: `${basePath}/${filename}_2x.avif`,
mobileImage1x: `${basePath}/${filename}_mobile.${ext}`,
mobileImage2x: `${basePath}/${filename}_mobile_2x.${ext}`,
mobileImage1xWebp: `${basePath}/${filename}_mobile.webp`,
mobileImage2xWebp: `${basePath}/${filename}_mobile_2x.webp`,
mobileImage1xAvif: `${basePath}/${filename}_mobile.avif`,
mobileImage2xAvif: `${basePath}/${filename}_mobile_2x.avif`
});
const getNumberFormatter = (locale, options) => {
return new Intl.NumberFormat(locale, options);
};
const getDateFormatter = (locale, options) => {
return new Intl.DateTimeFormat(
locale,
options || {
year: "numeric",
month: "long",
day: "numeric"
}
);
};
const getByKey = (obj, key) => {
return obj[key];
};
const convertPhoneMask = (eventValue) => {
let cleaned = "";
for (let i = 0; i < eventValue.length; i++) {
const char = eventValue[i];
if (i === 0 && char === "+") {
cleaned += "+";
} else if (/\d/.test(char)) {
cleaned += char;
}
}
if (cleaned === "+" || cleaned.length === 0) {
return "";
}
const valueArray = cleaned.split("");
const firstCharacter = valueArray[0];
const secondCharacter = valueArray[1];
if (firstCharacter === "7" || firstCharacter === "8") {
valueArray[0] = "+7";
} else if (firstCharacter === "+" && secondCharacter === "8") {
valueArray[1] = "8";
} else if (firstCharacter && firstCharacter !== "+") {
valueArray[0] = `+${firstCharacter}`;
}
let result = valueArray.join("").trim();
if (result.length > 16) {
result = result.substring(0, 16);
}
return result;
};
const getSubdomain = (host, SUB_DOMAIN) => {
if (!host) return SUB_DOMAIN.main;
const subdomain = host.split(".")[0];
const item = SUB_DOMAIN[subdomain];
if (!item) return SUB_DOMAIN.main;
return item;
};
const updateTextByTemplate = ({
text,
subdomain,
SUBDOMAIN_NAME,
SUBDOMAIN_MASK
}) => {
if (!subdomain || !SUBDOMAIN_NAME || !SUBDOMAIN_MASK) return text;
const key = SUBDOMAIN_NAME[subdomain];
if (!subdomain || !key) return text;
const subdomainData = getByKey(SUBDOMAIN_NAME, subdomain);
if (!subdomainData) return text;
let result = text;
const { name, declination, region, regionDeclination } = subdomainData;
const cityReg = new RegExp(SUBDOMAIN_MASK.CITY, "g");
const cityDeclReg = new RegExp(SUBDOMAIN_MASK.CITY_DECL, "g");
const cityRegionReg = new RegExp(SUBDOMAIN_MASK.CITY_REGION, "g");
const cityRegionDeclReg = new RegExp(SUBDOMAIN_MASK.CITY_REGION_DECL, "g");
result = result.replace(cityReg, name);
result = result.replace(cityDeclReg, declination);
result = result.replace(cityRegionReg, region);
result = result.replace(cityRegionDeclReg, regionDeclination);
return result;
};
const prepareLocalMetaData = ({
subdomain,
metaData,
host,
lang,
isSubdomain = true,
SUBDOMAIN_NAME,
SUBDOMAIN_MASK,
DEFAULT_SEO_TEXT
}) => {
const { title, description, keywords, canonical } = metaData;
let correctHost = subdomain === "main" ? host : `${subdomain}.${host}`;
if (!isSubdomain) {
correctHost = host;
}
let currentTitle = title;
let currentDescription = description;
let currentKeywords = keywords;
const alternates = {};
if (title) {
currentTitle = updateTextByTemplate({ text: title, subdomain, SUBDOMAIN_MASK, SUBDOMAIN_NAME });
} else {
currentTitle = updateTextByTemplate({
text: DEFAULT_SEO_TEXT.title,
subdomain,
SUBDOMAIN_MASK,
SUBDOMAIN_NAME
});
}
if (description) {
currentDescription = updateTextByTemplate({
text: description,
subdomain,
SUBDOMAIN_MASK,
SUBDOMAIN_NAME
});
} else {
currentDescription = updateTextByTemplate({
text: DEFAULT_SEO_TEXT.description,
subdomain,
SUBDOMAIN_MASK,
SUBDOMAIN_NAME
});
}
if (keywords) {
currentKeywords = updateTextByTemplate({
text: keywords,
subdomain,
SUBDOMAIN_MASK,
SUBDOMAIN_NAME
});
} else {
currentKeywords = updateTextByTemplate({
text: DEFAULT_SEO_TEXT.keywords,
subdomain,
SUBDOMAIN_MASK,
SUBDOMAIN_NAME
});
}
if (canonical !== void 0) {
alternates.canonical = `https://${correctHost}${canonical}`;
}
if (lang) {
const langs = lang.locales.filter((item) => item !== lang.locale);
const languages = {};
langs.forEach((item) => {
let url2 = `https://${correctHost}/${item}`;
if (lang.city) {
url2 += `/${lang.city}`;
}
url2 += lang.route[0] === "/" ? lang.route : `/${lang.route}`;
languages[item] = url2;
});
let url = ``;
if (lang.locale !== lang.defaultLocale) {
url += `/${lang.locale}`;
}
if (lang.city) {
url += `/${lang.city}`;
}
url += lang.route[0] === "/" ? lang.route : `/${lang.route}`;
alternates.canonical = `https://${correctHost}${url}`;
alternates.languages = languages;
}
return {
title: currentTitle,
description: currentDescription,
keywords: currentKeywords,
alternates: Object.keys(alternates).length ? alternates : void 0
};
};
const parseStringToKeyValue = (input) => {
const decoded = decodeURI(input);
const cleanedInput = decoded.replace(/^\/[^\/]*\//, "");
const keyValuePairs = cleanedInput.split("--");
const result = {};
keyValuePairs.forEach((pair) => {
const [key, value] = pair.split("__");
if (key && value) {
result[key] = value.replace(/_/g, " ");
}
});
return result;
};
const prepareColor = ({
color1,
color2,
notFoundText,
COLORS_NAMES
}) => {
const name1 = COLORS_NAMES[color1];
const name2 = color2 ? COLORS_NAMES[color2] : null;
if (name1 && name2) {
return `${name1}/${name2}`;
} else if (name1) {
return name1;
} else {
return notFoundText;
}
};
const generatePaginationArray = (pagination, baseUrl, initialParams) => {
if (!pagination) return { buttons: [] };
const { page, pages } = pagination;
if (!page || !pages) {
return { buttons: [] };
}
const params = new URLSearchParams(initialParams);
const paginationArray = [];
const maxVisibleButtons = 8;
const halfMaxVisibleButtons = Math.floor(maxVisibleButtons / 2);
let startPage = Math.max(1, page - halfMaxVisibleButtons);
let endPage = Math.min(pages, page + halfMaxVisibleButtons);
if (endPage - startPage + 1 < maxVisibleButtons) {
startPage = Math.max(1, endPage - maxVisibleButtons + 1);
endPage = Math.min(pages, startPage + maxVisibleButtons - 1);
}
for (let i = startPage; i <= endPage; i++) {
const currentParams = new URLSearchParams(params);
currentParams.set("page", i.toString());
paginationArray.push({
label: i.toString(),
href: `${baseUrl}?${currentParams.toString()}`,
isActive: i === page
});
}
const containsFirstPage = paginationArray.some((btn) => btn.label === "1");
const firstPage = containsFirstPage ? void 0 : {
label: "1",
href: `${baseUrl}?${new URLSearchParams({ ...Object.fromEntries(params), page: "1" }).toString()}`,
isActive: page === 1
};
const containsLastPage = paginationArray.some((btn) => btn.label === pages.toString());
const lastPage = containsLastPage ? void 0 : {
label: pages.toString(),
href: `${baseUrl}?${new URLSearchParams({ ...Object.fromEntries(params), page: pages.toString() }).toString()}`,
isActive: page === pages
};
return {
buttons: paginationArray,
firstPage,
lastPage
};
};
const arrayToKeyValueObject = (arr) => {
return arr.reduce(
(acc, item) => {
acc[item] = item;
return acc;
},
{}
);
};
const preparePageParam = (page) => {
if (!page) return 1;
if (typeof page === "number") {
if (page < 1) return 1;
return page;
}
if (typeof page === "string") {
const parsed = parseInt(page);
if (Number.isNaN(parsed)) return 1;
return parsed;
}
return 1;
};
const isNotEmptyHtml = (html) => {
return !!html && html !== '<p class="content-paragraph" ></p>';
};
const createCityLink = (city, href) => {
return `/${city}${href}`;
};
const getLocaleField = ({
locale,
field,
data
}) => {
if (!data) return "";
const key = `${field}${locale.toUpperCase()}`;
const result = data[key] ?? "";
if (typeof result !== "string") return "";
return result;
};
const isBotUserAgent = (userAgent) => {
const botPatterns = [
"bot",
"crawler",
"spider",
"scraper",
"googlebot",
"bingbot",
"yandexbot",
"baiduspider",
"facebookexternalhit",
"twitterbot",
"whatsapp",
"pinterest",
"duckduckbot",
"slurp",
"archive.org",
"headless",
"phantomjs",
"selenium"
];
return botPatterns.some((pattern) => userAgent.toLowerCase().includes(pattern));
};
const generatePlaceholderColor = (seed) => {
const stringToHash = (str) => {
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash = hash & hash;
}
return Math.abs(hash);
};
let numericSeed;
if (seed !== void 0) {
if (typeof seed === "string") {
numericSeed = stringToHash(seed);
} else {
numericSeed = seed;
}
}
const getRandom = numericSeed !== void 0 ? (() => {
let val = (numericSeed * 9301 + 49297) % 233280;
return () => {
val = (val * 9301 + 49297) % 233280;
return val / 233280;
};
})() : Math.random;
const randomValue = getRandom();
let hue;
if (randomValue < 0.5) {
hue = Math.floor(randomValue * 2 * 90);
} else {
hue = 160 + Math.floor((randomValue - 0.5) * 2 * 200);
}
const saturation = 40 + getRandom() * 40;
const lightness = 50 + getRandom() * 30;
return hslToHex(hue, saturation, lightness);
};
const hslToHex = (h, s, l) => {
const normalizedH = h / 360;
const normalizedS = s / 100;
const normalizedL = l / 100;
let r2, g, b;
if (normalizedS === 0) {
r2 = g = b = normalizedL;
} else {
const hue2rgb = (p2, q2, t) => {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p2 + (q2 - p2) * 6 * t;
if (t < 1 / 2) return q2;
if (t < 2 / 3) return p2 + (q2 - p2) * (2 / 3 - t) * 6;
return p2;
};
const q = normalizedL < 0.5 ? normalizedL * (1 + normalizedS) : normalizedL + normalizedS - normalizedL * normalizedS;
const p = 2 * normalizedL - q;
r2 = hue2rgb(p, q, normalizedH + 1 / 3);
g = hue2rgb(p, q, normalizedH);
b = hue2rgb(p, q, normalizedH - 1 / 3);
}
const toHex = (x) => {
const hex = Math.round(x * 255).toString(16);
return hex.length === 1 ? "0" + hex : hex;
};
return `#${toHex(r2)}${toHex(g)}${toHex(b)}`;
};
const uuidToStringId = (uuid2, length = 18) => {
const cleanUuid = uuid2.replace(/-/g, "");
return cleanUuid.slice(-length);
};
const uuidToNumericId = (uuid2, maxDigits = 18) => {
const cleanUuid = uuid2.replace(/-/g, "");
let hash = 0;
for (let i = 0; i < cleanUuid.length; i++) {
const char = cleanUuid.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash = hash & hash;
}
let result = Math.abs(hash).toString();
if (result.length < maxDigits) {
const segments = cleanUuid.match(/.{1,4}/g) || [];
for (const segment of segments) {
const segmentNum = parseInt(segment, 16);
result += Math.abs(segmentNum).toString();
if (result.length >= maxDigits) break;
}
}
return result.slice(0, maxDigits);
};
const escapeXml = (str) => {
if (!str) return "";
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
};
const generateYandexFeedXML = ({
shopName,
shopCompany,
delivery,
categoriesData,
offersData,
host
}) => {
const url = `https://${host}`;
const offersXml = offersData.map((item) => {
var _a;
const id = typeof item.id === "number" ? item.id : uuidToNumericId(item.id);
const categoryId = typeof item.categoryId === "number" ? item.categoryId : uuidToNumericId(item.categoryId);
return `
<offer id="${id}" available="true">
<url>${escapeXml(`${url}${item.href}`)}</url>
<price>${item.price}</price>
<currencyId>RUR</currencyId>
<categoryId>${categoryId}</categoryId>
${item.images.length ? item.images.map((item2) => `<picture>${escapeXml(item2.image1x)}</picture>`).join("") : ""}
<name>${escapeXml(item.name)}</name>
<vendor>${escapeXml(item.vendor)}</vendor>
<description>${escapeXml(item.description)}</description>
${item.vendorCode ? `<vendorCode>${escapeXml(item.vendorCode)}</vendorCode>` : ""}
<pickup>${item.pickup}</pickup>
${(_a = item.params) == null ? void 0 : _a.map((item2) => {
return `<param name="${item2.name}">${escapeXml(item2.value)}</param>`;
}).join("")}
</offer>
`;
}).join("");
const categoriesXml = categoriesData.map((item) => {
const id = typeof item.id === "number" ? item.id : uuidToNumericId(item.id);
const parentId = item.parentId ? ` parentId="${typeof item.parentId === "number" ? item.parentId : uuidToNumericId(item.parentId)}"` : "";
return `<category id="${id}"${parentId}>${escapeXml(item.name)}</category>`;
}).join("");
return `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE yml_catalog SYSTEM "shops.dtd">
<yml_catalog date="${(/* @__PURE__ */ new Date()).toISOString()}">
<shop>
<name>${escapeXml(shopName)}</name>
<company>${escapeXml(shopCompany)}</company>
<url>${url}</url>
<delivery>${delivery}</delivery>
<currencies>
<currency id="RUR" rate="1"/>
</currencies>
<categories>
${categoriesXml}
</categories>
<offers>
${offersXml}
</offers>
</shop>
</yml_catalog>`;
};
function r(e) {
var t, f, n = "";
if ("string" == typeof e || "number" == typeof e) n += e;
else if ("object" == typeof e) if (Array.isArray(e)) {
var o = e.length;
for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
} else for (f in e) e[f] && (n && (n += " "), n += f);
return n;
}
function clsx() {
for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
return n;
}
const CLASS_PART_SEPARATOR = "-";
const createClassGroupUtils = (config2) => {
const classMap = createClassMap(config2);
const {
conflictingClassGroups,
conflictingClassGroupModifiers
} = config2;
const getClassGroupId = (className) => {
const classParts = className.split(CLASS_PART_SEPARATOR);
if (classParts[0] === "" && classParts.length !== 1) {
classParts.shift();
}
return getGroupRecursive(classParts, classMap) || getGroupIdForArbitraryProperty(className);
};
const getConflictingClassGroupIds = (classGroupId, hasPostfixModifier) => {
const conflicts = conflictingClassGroups[classGroupId] || [];
if (hasPostfixModifier && conflictingClassGroupModifiers[classGroupId]) {
return [...conflicts, ...conflictingClassGroupModifiers[classGroupId]];
}
return conflicts;
};
return {
getClassGroupId,
getConflictingClassGroupIds
};
};
const getGroupRecursive = (classParts, classPartObject) => {
var _a;
if (classParts.length === 0) {
return classPartObject.classGroupId;
}
const currentClassPart = classParts[0];
const nextClassPartObject = classPartObject.nextPart.get(currentClassPart);
const classGroupFromNextClassPart = nextClassPartObject ? getGroupRecursive(classParts.slice(1), nextClassPartObject) : void 0;
if (classGroupFromNextClassPart) {
return classGroupFromNextClassPart;
}
if (classPartObject.validators.length === 0) {
return void 0;
}
const classRest = classParts.join(CLASS_PART_SEPARATOR);
return (_a = classPartObject.validators.find(({
validator
}) => validator(classRest))) == null ? void 0 : _a.classGroupId;
};
const arbitraryPropertyRegex = /^\[(.+)\]$/;
const getGroupIdForArbitraryProperty = (className) => {
if (arbitraryPropertyRegex.test(className)) {
const arbitraryPropertyClassName = arbitraryPropertyRegex.exec(className)[1];
const property = arbitraryPropertyClassName == null ? void 0 : arbitraryPropertyClassName.substring(0, arbitraryPropertyClassName.indexOf(":"));
if (property) {
return "arbitrary.." + property;
}
}
};
const createClassMap = (config2) => {
const {
theme,
classGroups
} = config2;
const classMap = {
nextPart: /* @__PURE__ */ new Map(),
validators: []
};
for (const classGroupId in classGroups) {
processClassesRecursively(classGroups[classGroupId], classMap, classGroupId, theme);
}
return classMap;
};
const processClassesRecursively = (classGroup, classPartObject, classGroupId, theme) => {
classGroup.forEach((classDefinition) => {
if (typeof classDefinition === "string") {
const classPartObjectToEdit = classDefinition === "" ? classPartObject : getPart(classPartObject, classDefinition);
classPartObjectToEdit.classGroupId = classGroupId;
return;
}
if (typeof classDefinition === "function") {
if (isThemeGetter(classDefinition)) {
processClassesRecursively(classDefinition(theme), classPartObject, classGroupId, theme);
return;
}
classPartObject.validators.push({
validator: classDefinition,
classGroupId
});
return;
}
Object.entries(classDefinition).forEach(([key, classGroup2]) => {
processClassesRecursively(classGroup2, getPart(classPartObject, key), classGroupId, theme);
});
});
};
const getPart = (classPartObject, path) => {
let currentClassPartObject = classPartObject;
path.split(CLASS_PART_SEPARATOR).forEach((pathPart) => {
if (!currentClassPartObject.nextPart.has(pathPart)) {
currentClassPartObject.nextPart.set(pathPart, {
nextPart: /* @__PURE__ */ new Map(),
validators: []
});
}
currentClassPartObject = currentClassPartObject.nextPart.get(pathPart);
});
return currentClassPartObject;
};
const isThemeGetter = (func) => func.isThemeGetter;
const createLruCache = (maxCacheSize) => {
if (maxCacheSize < 1) {
return {
get: () => void 0,
set: () => {
}
};
}
let cacheSize = 0;
let cache = /* @__PURE__ */ new Map();
let previousCache = /* @__PURE__ */ new Map();
const update = (key, value) => {
cache.set(key, value);
cacheSize++;
if (cacheSize > maxCacheSize) {
cacheSize = 0;
previousCache = cache;
cache = /* @__PURE__ */ new Map();
}
};
return {
get(key) {
let value = cache.get(key);
if (value !== void 0) {
return value;
}
if ((value = previousCache.get(key)) !== void 0) {
update(key, value);
return value;
}
},
set(key, value) {
if (cache.has(key)) {
cache.set(key, value);
} else {
update(key, value);
}
}
};
};
const IMPORTANT_MODIFIER = "!";
const MODIFIER_SEPARATOR = ":";
const MODIFIER_SEPARATOR_LENGTH = MODIFIER_SEPARATOR.length;
const createParseClassName = (config2) => {
const {
prefix,
experimentalParseClassName
} = config2;
let parseClassName = (className) => {
const modifiers = [];
let bracketDepth = 0;
let parenDepth = 0;
let modifierStart = 0;
let postfixModifierPosition;
for (let index = 0; index < className.length; index++) {
let currentCharacter = className[index];
if (bracketDepth === 0 && parenDepth === 0) {
if (currentCharacter === MODIFIER_SEPARATOR) {
modifiers.push(className.slice(modifierStart, index));
modifierStart = index + MODIFIER_SEPARATOR_LENGTH;
continue;
}
if (currentCharacter === "/") {
postfixModifierPosition = index;
continue;
}
}
if (currentCharacter === "[") {
bracketDepth++;
} else if (currentCharacter === "]") {
bracketDepth--;
} else if (currentCharacter === "(") {
parenDepth++;
} else if (currentCharacter === ")") {
parenDepth--;
}
}
const baseClassNameWithImportantModifier = modifiers.length === 0 ? className : className.substring(modifierStart);
const baseClassName = stripImportantModifier(baseClassNameWithImportantModifier);
const hasImportantModifier = baseClassName !== baseClassNameWithImportantModifier;
const maybePostfixModifierPosition = postfixModifierPosition && postfixModifierPosition > modifierStart ? postfixModifierPosition - modifierStart : void 0;
return {
modifiers,
hasImportantModifier,
baseClassName,
maybePostfixModifierPosition
};
};
if (prefix) {
const fullPrefix = prefix + MODIFIER_SEPARATOR;
const parseClassNameOriginal = parseClassName;
parseClassName = (className) => className.startsWith(fullPrefix) ? parseClassNameOriginal(className.substring(fullPrefix.length)) : {
isExternal: true,
modifiers: [],
hasImportantModifier: false,
baseClassName: className,
maybePostfixModifierPosition: void 0
};
}
if (experimentalParseClassName) {
const parseClassNameOriginal = parseClassName;
parseClassName = (className) => experimentalParseClassName({
className,
parseClassName: parseClassNameOriginal
});
}
return parseClassName;
};
const stripImportantModifier = (baseClassName) => {
if (baseClassName.endsWith(IMPORTANT_MODIFIER)) {
return baseClassName.substring(0, baseClassName.length - 1);
}
if (baseClassName.startsWith(IMPORTANT_MODIFIER)) {
return baseClassName.substring(1);
}
return baseClassName;
};
const createSortModifiers = (config2) => {
const orderSensitiveModifiers = Object.fromEntries(config2.orderSensitiveModifiers.map((modifier) => [modifier, true]));
const sortModifiers = (modifiers) => {
if (modifiers.length <= 1) {
return modifiers;
}
const sortedModifiers = [];
let unsortedModifiers = [];
modifiers.forEach((modifier) => {
const isPositionSensitive = modifier[0] === "[" || orderSensitiveModifiers[modifier];
if (isPositionSensitive) {
sortedModifiers.push(...unsortedModifiers.sort(), modifier);
unsortedModifiers = [];
} else {
unsortedModifiers.push(modifier);
}
});
sortedModifiers.push(...unsortedModifiers.sort());
return sortedModifiers;
};
return sortModifiers;
};
const createConfigUtils = (config2) => ({
cache: createLruCache(config2.cacheSize),
parseClassName: createParseClassName(config2),
sortModifiers: createSortModifiers(config2),
...createClassGroupUtils(config2)
});
const SPLIT_CLASSES_REGEX = /\s+/;
const mergeClassList = (classList, configUtils) => {
const {
parseClassName,
getClassGroupId,
getConflictingClassGroupIds,
sortModifiers
} = configUtils;
const classGroupsInConflict = [];
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 = 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;
};
function twJoin() {
let index = 0;
let argument;
let resolvedValue;
let string2 = "";
while (index < arguments.length) {
if (argument = arguments[index++]) {
if (resolvedValue = toValue(argument)) {
string2 && (string2 += " ");
string2 += resolvedValue;
}
}
}
return string2;
}
const toValue = (mix) => {
if (typeof mix === "string") {
return mix;
}
let resolvedValue;
let string2 = "";
for (let k = 0; k < mix.length; k++) {
if (mix[k]) {
if (resolvedValue = toValue(mix[k])) {
string2 && (string2 += " ");
string2 += resolvedValue;
}
}
}
return string2;
};
function createTailwindMerge(createConfigFirst, ...createConfigRest) {
let configUtils;
let cacheGet;
let cacheSet;
let functionToCall = initTailwindMerge;
function initTailwindMerge(classList) {
const config2 = createConfigRest.reduce((previousConfig, createConfigCurrent) => createConfigCurrent(previousConfig), createConfigFirst());
configUtils = createConfigUtils(config2);
cacheGet = configUtils.cache.get;
cacheSet = configUtils.cache.set;
functionToCall = tailwindMerge;
return tailwindMerge(classList);
}
function tailwindMerge(classList) {
const cachedResult = cacheGet(classList);
if (cachedResult) {
return cachedResult;
}
const result = mergeClassList(classList, configUtils);
cacheSet(classList, result);
return result;
}
return function callTailwindMerge() {
return functionToCall(twJoin.apply(null, arguments));
};
}
const fromTheme = (key) => {
const themeGetter = (theme) => theme[key] || [];
themeGetter.isThemeGetter = true;
return themeGetter;
};
const arbitraryValueRegex = /^\[(?:(\w[\w-]*):)?(.+)\]$/i;
const arbitraryVariableRegex = /^\((?:(\w[\w-]*):)?(.+)\)$/i;
const fractionRegex = /^\d+\/\d+$/;
const tshirtUnitRegex = /^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/;
const lengthUnitRegex = /\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\b(calc|min|max|clamp)\(.+\)|^0$/;
const colorFunctionRegex = /^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/;
const shadowRegex = /^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/;
const imageRegex = /^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/;
const isFraction = (value) => fractionRegex.test(value);
const isNumber = (value) => !!value && !Number.isNaN(Number(value));
const isInteger = (value) => !!value && Number.isInteger(Number(value));
const isPercent = (value) => value.endsWith("%") && isNumber(value.slice(0, -1));
const isTshirtSize = (value) => tshirtUnitRegex.test(value);
const isAny = () => true;
const isLengthOnly = (value) => (
// `colorFunctionRegex` check is necessary because color functions can have percentages in them which which would be incorrectly classified as lengths.
// For example, `hsl(0 0% 0%)` would be classified as a length without this check.
// I could also use lookbehind assertion in `lengthUnitRegex` but that isn't supported widely enough.
lengthUnitRegex.test(value) && !colorFunctionRegex.test(value)
);
const isNever = () => false;
const isShadow = (value) => shadowRegex.test(value);
const isImage = (value) => imageRegex.test(value);
const isAnyNonArbitrary = (value) => !isArbitraryValue(value) && !isArbitraryVariable(value);
const isArbitrarySize = (value) => getIsArbitraryValue(value, isLabelSize, isNever);
const isArbitraryValue = (value) => arbitraryValueRegex.test(value);
const isArbitraryLength = (value) => getIsArbitraryValue(value, isLabelLength, isLengthOnly);
const isArbitraryNumber = (value) => getIsArbitraryValue(value, isLabelNumber, isNumber);
const isArbitraryPosition = (value) => getIsArbitraryValue(value, isLabelPosition, isNever);
const isArbitraryImage = (value) => getIsArbitraryValue(value, isLabelImage, isImage);
const isArbitraryShadow = (value) => getIsArbitraryValue(value, isLabelShadow, isShadow);
const isArbitraryVariable = (value) => arbitraryVariableRegex.test(value);
const isArbitraryVariableLength = (value) => getIsArbitraryVariable(value, isLabelLength);
const isArbitraryVariableFamilyName = (value) => getIsArbitraryVariable(value, isLabelFamilyName);
const isArbitraryVariablePosition = (value) => getIsArbitraryVariable(value, isLabelPosition);
const isArbitraryVariableSize = (value) => getIsArbitraryVariable(value, isLabelSize);
const isArbitraryVariableImage = (value) => getIsArbitraryVariable(value, isLabelImage);
const isArbitraryVariableShadow = (value) => getIsArbitraryVariable(value, isLabelShadow, true);
const getIsArbitraryValue = (value, testLabel, testValue) => {
const result = arbitraryValueRegex.exec(value);
if (result) {
if (result[1]) {
return testLabel(result[1]);
}
return testValue(result[2]);
}
return false;
};
const getIsArbitraryVariable = (value, testLabel, shouldMatchNoLabel = false) => {
const result = arbitraryVariableRegex.exec(value);
if (result) {
if (result[1]) {
return testLabel(result[1]);
}
return shouldMatchNoLabel;
}
return false;
};
const isLabelPosition = (label) => label === "position" || label === "percentage";
const isLabelImage = (label) => label === "image" || label === "url";
const isLabelSize = (label) => label === "length" || label === "size" || label === "bg-size";
const isLabelLength = (label) => label === "length";
const isLabelNumber = (label) => label === "number";
const isLabelFamilyName = (label) => label === "family-name";
const isLabelShadow = (label) => label === "shadow";
const getDefaultConfig = () => {
const themeColor = fromTheme("color");
const themeFont = fromTheme("font");
const themeText = fromTheme("text");
const themeFontWeight = fromTheme("font-weight");
const themeTracking = fromTheme("tracking");
const themeLeading = fromTheme("leading");
const themeBreakpoint = fromTheme("breakpoint");
const themeContainer = fromTheme("container");
const themeSpacing = fromTheme("spacing");
const themeRadius = fromTheme("radius");
const themeShadow = fromTheme("shadow");
const themeInsetShadow = fromTheme("inset-shadow");
const themeTextShadow = fromTheme("text-shadow");
const themeDropShadow = fromTheme("drop-shadow");
const themeBlur = fromTheme("blur");
const themePerspective = fromTheme("perspective");
const themeAspect = fromTheme("aspect");
const themeEase = fromTheme("ease");
const themeAnimate = fromTheme("animate");
const scaleBreak = () => ["auto", "avoid", "all", "avoid-page", "page", "left", "right", "column"];
const scalePosition = () => [
"center",
"top",
"bottom",
"left",
"right",
"top-left",
// Deprecated since Tailwind CSS v4.1.0, see https://github.com/tailwindlabs/tailwindcss/pull/17378
"left-top",
"top-right",
// Deprecated since Tailwind CSS v4.1.0, see https://github.com/tailwindlabs/tailwindcss/pull/17378
"right-top",
"bottom-right",
// Deprecated since Tailwind CSS v4.1.0, see https://github.com/tailwindlabs/tailwindcss/pull/17378
"right-bottom",
"bottom-left",
// Deprecated since Tailwind CSS v4.1.0, see https://github.com/tailwindlabs/tailwindcss/pull/17378
"left-bottom"
];
const scalePositionWithArbitrary = () => [...scalePosition(), isArbitraryVariable, isArbitraryValue];
const scaleOverflow = () => ["auto", "hidden", "clip", "visible", "scroll"];
const scaleOverscroll = () => ["auto", "contain", "none"];
const scaleUnambiguousSpacing = () => [isArbitraryVariable, isArbitraryValue, themeSpacing];
const scaleInset = () => [isFraction, "full", "auto", ...scaleUnambiguousSpacing()];
const scaleGridTemplateColsRows = () => [isInteger, "none", "subgrid", isArbitraryVariable, isArbitraryValue];
const scaleGridColRowStartAndEnd = () => ["auto", {
span: ["full", isInteger, isArbitraryVariable, isArbitraryValue]
}, isInteger, isArbitraryVariable, isArbitraryValue];
const scaleGridColRowStartOrEnd = () => [isInteger, "auto", isArbitraryVariable, isArbitraryValue];
const scaleGridAutoColsRows = () => ["auto", "min", "max", "fr", isArbitraryVariable, isArbitraryValue];
const scaleAlignPrimaryAxis = () => ["start", "end", "center", "between", "around", "evenly", "stretch", "baseline", "center-safe", "end-safe"];
const scaleAlignSecondaryAxis = () => ["start", "end", "center", "stretch", "center-safe", "end-safe"];
const scaleMargin = () => ["auto", ...scaleUnambiguousSpacing()];
const scaleSizing = () => [isFraction, "auto", "full", "dvw", "dvh", "lvw", "lvh", "svw", "svh", "min", "max", "fit", ...scaleUnambiguousSpacing()];
const scaleColor = () => [themeColor, isArbitraryVariable, isArbitraryValue];
const scaleBgPosition = () => [...scalePosition(), isArbitraryVariablePosition, isArbitraryPosition, {
position: [isArbitraryVariable, isArbitraryValue]
}];
const scaleBgRepeat = () => ["no-repeat", {
repeat: ["", "x", "y", "space", "round"]
}];
const scaleBgSize = () => ["auto", "cover", "contain", isArbitraryVariableSize, isArbitrarySize, {
size: [isArbitraryVariable, isArbitraryValue]
}];
const scaleGradientStopPosition = () => [isPercent, isArbitraryVariableLength, isArbitraryLength];
const scaleRadius = () => [
// Deprecated since Tailwind CSS v4.0.0
"",
"none",
"full",
themeRadius,
isArbitraryVariable,
isArbitraryValue
];
const scaleBorderWidth = () => ["", isNumber, isArbitraryVariableLength, isArbitraryLength];
const scaleLineStyle = () => ["solid", "dashed", "dotted", "double"];
const scaleBlendMode = () => ["normal", "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn", "hard-light", "soft-light", "difference", "exclusion", "hue", "saturation", "color", "luminosity"];
const scaleMaskImagePosition = () => [isNumber, isPercent, isArbitraryVariablePosition, isArbitraryPosition];
const scaleBlur = () => [
// Deprecated since Tailwind CSS v4.0.0
"",
"none",
themeBlur,
isArbitraryVariable,
isArbitraryValue
];
const scaleRotate = () => ["none", isNumber, isArbitraryVariable, isArbitraryValue];
const scaleScale = () => ["none", isNumber, isArbitraryVariable, isArbitraryValue];
const scaleSkew = () => [isNumber, isArbitraryVariable, isArbitraryValue];
const scaleTranslate = () => [isFraction, "full", ...scaleUnambiguousSpacing()];
return {
cacheSize: 500,
theme: {
animate: ["spin", "ping", "pulse", "bounce"],
aspect: ["video"],
blur: [isTshirtSize],
breakpoint: [isTshirtSize],
color: [isAny],
container: [isTshirtSize],
"drop-shadow": [isTshirtSize],
ease: ["in", "out", "in-out"],
font: [isAnyNonArbitrary],
"font-weight": ["thin", "extralight", "light", "normal", "medium", "semibold", "bold", "extrabold", "black"],
"inset-shadow": [isTshirtSize],
leading: ["none", "tight", "snug", "normal", "relaxed", "loose"],
perspective: ["dramatic", "near", "normal", "midrange", "distant", "none"],
radius: [isTshirtSize],
shadow: [isTshirtSize],
spacing: ["px", isNumber],
text: [isTshirtSize],
"text-shadow": [isTshirtSize],
tracking: ["tighter", "tight", "normal", "wide", "wider", "widest"]
},
classGroups: {
// --------------
// --- Layout ---
// --------------
/**
* Aspect Ratio
* @see https://tailwindcss.com/docs/aspect-ratio
*/
aspect: [{
aspect: ["auto", "square", isFraction, isArbitraryValue, isArbitraryVariable, themeAspect]
}],
/**
* Container
* @see https://tailwindcss.com/docs/container
* @deprecated since Tailwind CSS v4.0.0
*/
container: ["container"],
/**
* Columns
* @see https://tailwindcss.com/docs/columns
*/
columns: [{
columns: [isNumber, isArbitraryValue, isArbitraryVariable, themeContainer]
}],
/**
* Break After
* @see https://tailwindcss.com/docs/break-after
*/
"break-after": [{
"break-after": scaleBreak()
}],
/**
* Break Before
* @see https://tailwindcss.com/docs/break-before
*/
"break-before": [{
"break-before": scaleBreak()
}],
/**
* Break Inside
* @see https://tailwindcss.com/docs/break-inside
*/
"break-inside": [{
"break-inside": ["auto", "avoid", "avoid-page", "avoid-column"]
}],
/**
* Box Decoration Break
* @see https://tailwindcss.com/docs/box-decoration-break
*/
"box-decoration": [{
"box-decoration": ["slice", "clone"]
}],
/**
* Box Sizing
* @see https://tailwindcss.com/docs/box-sizing
*/
box: [{
box: ["border", "content"]
}],
/**
* Display
* @see https://tailwindcss.com/docs/display
*/
display: ["block", "inline-block", "inline", "flex", "inline-flex", "table", "inline-table", "table-caption", "table-cell", "table-column", "table-column-group", "table-footer-group", "table-header-group", "table-row-group", "table-row", "flow-root", "grid", "inline-grid", "contents", "list-item", "hidden"],
/**
* Screen Reader Only
* @see https://tailwindcss.com/docs/display#screen-reader-only
*/
sr: ["sr-only", "not-sr-only"],
/**
* Floats
* @see https://tailwindcss.com/docs/float
*/
float: [{
float: ["right", "left", "none", "start", "end"]
}],
/**
* Clear
* @see https://tailwindcss.com/docs/clear
*/
clear: [{
clear: ["left", "right", "both", "none", "start", "end"]
}],
/**
* Isolation
* @see https://tailwindcss.com/docs/isolation
*/
isolation: ["isolate", "isolation-auto"],
/**
* Object Fit
* @see https://tailwindcss.com/docs/object-fit
*/
"object-fit": [{
object: ["contain", "cover", "fill", "none", "scale-down"]
}],
/**
* Object Position
* @see https://tailwindcss.com/docs/object-position
*/
"object-position": [{
object: scalePositionWithArbitrary()
}],
/**
* Overflow
* @see https://tailwindcss.com/docs/overflow
*/
overflow: [{
overflow: scaleOverflow()
}],
/**
* Overflow X
* @see https://tailwindcss.com/docs/overflow
*/
"overflow-x": [{
"overflow-x": scaleOverflow()
}],
/**
* Overflow Y
* @see https://tailwindcss.com/docs/overflow
*/
"overflow-y": [{
"overflow-y": scaleOverflow()
}],
/**
* Overscroll Behavior
* @see https://tailwindcss.com/docs/overscroll-behavior
*/
overscroll: [{
overscroll: scaleOverscroll()
}],
/**
* Overscroll Behavior X
* @see https://tailwindcss.com/docs/overscroll-behavior
*/
"overscroll-x": [{
"overscroll-x": scaleOverscroll()
}],
/**
* Overscroll Behavior Y
* @see https://tailwindcss.com/docs/overscroll-behavior
*/
"overscroll-y": [{
"overscroll-y": scaleOverscroll()
}],
/**
* Position
* @see https://tailwindcss.com/docs/position
*/
position: ["static", "fixed", "absolute", "relative", "sticky"],
/**
* Top / Right / Bottom / Left
* @see https://tailwindcss.com/docs/top-right-bottom-left
*/
inset: [{
inset: scaleInset()
}],
/**
* Right / Left
* @see https://tailwindcss.com/docs/top-right-bottom-left
*/
"inset-x": [{
"inset-x": scaleInset()
}],
/**
* Top / Bottom
* @see https://tailwindcss.com/docs/top-right-bottom-left
*/
"inset-y": [{
"inset-y": scaleInset()
}],
/**
* Start
* @see https://tailwindcss.com/docs/top-right-bottom-left
*/
start: [{
start: scaleInset()
}],
/**
* End
* @see https://tailwindcss.com/docs/top-right-bottom-left
*/
end: [{
end: scaleInset()
}],
/**
* Top
* @see https://tailwindcss.com/docs/top-right-bottom-left
*/
top: [{
top: scaleInset()
}],
/**
* Right
* @see https://tailwindcss.com/docs/top-right-bottom-left
*/
right: [{
right: scaleInset()
}],
/**
* Bottom
* @see https://tailwindcss.com/docs/top-right-bottom-left
*/
bottom: [{
bottom: scaleInset()
}],
/**
* Left
* @see https://tailwindcss.com/docs/top-right-bottom-left
*/
left: [{
left: scaleInset()
}],
/**
* Visibility
* @see https://tailwindcss.com/docs/visibility
*/
visibility: ["visible", "invisible", "collapse"],
/**
* Z-Index
* @see https://tailwindcss.com/docs/z-index
*/
z: [{
z: [isInteger, "auto", isArbitraryVariable, isArbitraryValue]
}],
// ------------------------
// --- Flexbox and Grid ---
// ------------------------
/**
* Flex Basis
* @see https://tailwindcss.com/docs/flex-basis
*/
basis: [{
basis: [isFraction, "full", "auto", themeContainer, ...scaleUnambiguousSpacing()]
}],
/**
* Flex Direction
* @see https://tailwindcss.com/docs/flex-direction
*/
"flex-direction": [{
flex: ["row", "row-reverse", "col", "col-reverse"]
}],
/**
* Flex Wrap
* @see https://tailwindcss.com/docs/flex-wrap
*/
"flex-wrap": [{
flex: ["nowrap", "wrap", "wrap-reverse"]
}],
/**
* Flex
* @see https://tailwindcss.com/docs/flex
*/
flex: [{
flex: [isNumber, isFraction, "auto", "initial", "none", isArbitraryValue]
}],
/**
* Flex Grow
* @see https://tailwindcss.com/docs/flex-grow
*/
grow: [{
grow: ["", isNumber, isArbitraryVariable, isArbitraryValue]
}],
/**
* Flex Shrink
* @see https://tailwindcss.com/docs/flex-shrink
*/
shrink: [{
shrink: ["", isNumber, isArbitraryVariable, isArbitraryValue]
}],
/**
* Order
* @see https://tailwindcss.com/docs/order
*/
order: [{
order: [isInteger, "first", "last", "none", isArbitraryVariable, isArbitraryValue]
}],
/**
* Grid Template Columns
* @see https://tailwindcss.com/docs/grid-template-columns
*/
"grid-cols": [{
"grid-cols": scaleGridTemplateColsRows()
}],
/**
* Grid Column Start / End
* @see https://tailwindcss.com/docs/grid-column
*/
"col-start-end": [{
col: scaleGridColRowStartAndEnd()
}],
/**
* Grid Column Start
* @see https://tailwindcss.com/docs/grid-column
*/
"col-start": [{
"col-start": scaleGridColRowStartOrEnd()
}],
/**
* Grid Column End
* @see https://tailwindcss.com/docs/grid-column
*/
"col-end": [{
"col-end": scaleGridColRowStartOrEnd()
}],
/**
* Grid Template Rows
* @see https://tailwindcss.com/docs/grid-template-rows
*/
"grid-rows": [{
"grid-rows": scaleGridTemplateColsRows()
}],
/**
* Grid Row Start / End
* @see https://tailwindcss.com/docs/grid-row
*/
"row-start-end": [{
row: scaleGridColRowStartAndEnd()
}],
/**
* Grid Row Start
* @see https://tailwindcss.com/docs/grid-row
*/
"row-start": [{
"row-start": scaleGridColRowStartOrEnd()
}],
/**
* Grid Row End
* @see https://tailwindcss.com/docs/grid-row
*/
"row-end": [{
"row-end": scaleGridColRowStartOrEnd()
}],
/**
* Grid Auto Flow
* @see https://tailwindcss.com/docs/grid-auto-flow
*/
"grid-flow": [{
"grid-flow": ["row", "col", "dense", "row-dense", "col-dense"]
}],
/**
* Grid Auto Columns
* @see https://tailwindcss.com/docs/grid-auto-columns
*/
"auto-cols": [{
"auto-cols": scaleGridAutoColsRows()
}],
/**
* Grid Auto Rows
* @see https://tailwindcss.com/docs/grid-auto-rows
*/
"auto-rows": [{
"auto-rows": scaleGridAutoColsRows()
}],
/**
* Gap
* @see https://tailwindcss.com/docs/gap
*/
gap: [{
gap: scaleUnambiguousSpacing()
}],
/**
* Gap X
* @see https://tailwindcss.com/docs/gap
*/
"gap-x": [{
"gap-x": scaleUnambiguousSpacing()
}],
/**
* Gap Y
* @see https://tailwindcss.com/docs/gap
*/
"gap-y": [{
"gap-y": scaleUnambiguousSpacing()
}],
/**
* Justify Content
* @see https://tailwindcss.com/docs/justify-content
*/
"justify-content": [{
justify: [...scaleAlignPrimaryAxis(), "normal"]
}],
/**
* Justify Items
* @see https://tailwindcss.com/docs/justify-items
*/
"justify-items": [{
"justify-items": [...scaleAlignSecondaryAxis(), "normal"]
}],
/**
* Justify Self
* @see https://tailwindcss.com/docs/justify-self
*/
"justify-self": [{
"justify-self": ["auto", ...scaleAlignSecondaryAxis()]
}],
/**
* Align Content
* @see https://tailwindcss.com/docs/align-content
*/
"align-content": [{
content: ["normal", ...scaleAlignPrimaryAxis()]
}],
/**
* Align Items
* @see https://tailwindcss.com/docs/align-items
*/
"align-items": [{
items: [...scaleAlignSecondaryAxis(), {
baseline: ["", "last"]
}]
}],
/**
* Align Self
* @see https://tailwindcss.com/docs/align-self
*/
"align-self": [{
self: ["auto", ...scaleAlignSecondaryAxis(), {
baseline: ["", "last"]
}]
}],
/**
* Place Content
* @see https://tailwindcss.com/docs/place-content
*/
"place-content": [{
"place-content": scaleAlignPrimaryAxis()
}],
/**
* Place Items
* @see https://tailwindcss.com/docs/place-items
*/
"place-items": [{
"place-items": [...scaleAlignSecondaryAxis(), "baseline"]
}],
/**
* Place Self
* @see https://tailwindcss.com/docs/place-self
*/
"place-self": [{
"place-self": ["auto", ...scaleAlignSecondaryAxis()]
}],
// Spacing
/**
* Padding
* @see https://tailwindcss.com/docs/padding
*/
p: [{
p: scaleUnambiguousSpacing()
}],
/**
* Padding X
* @see https://tailwindcss.com/docs/padding
*/
px: [{
px: scaleUnambiguousSpacing()
}],
/**
* Padding Y
* @see https://tailwindcss.com/docs/padding
*/
py: [{
py: scaleUnambiguousSpacing()
}],
/**
* Padding Start
* @see https://tailwindcss.com/docs/padding
*/
ps: [{
ps: scaleUnambiguousSpacing()
}],
/**
* Padding End
* @see https://tailwindcss.com/docs/padding
*/
pe: [{
pe: scaleUnambiguousSpacing()
}],
/**
* Padding Top
* @see https://tailwindcss.com/docs/padding
*/
pt: [{
pt: scaleUnambiguousSpacing()
}],
/**
* Padding Right
* @see https://tailwindcss.com/docs/padding
*/
pr: [{
pr: sc