first commit

This commit is contained in:
root
2025-12-28 20:50:08 +00:00
commit b1cd61c7b1
16845 changed files with 1594292 additions and 0 deletions

16
node_modules/tailwind-merge/src/index.ts generated vendored Normal file
View File

@@ -0,0 +1,16 @@
import { twJoin } from './lib/tw-join'
export { createTailwindMerge } from './lib/create-tailwind-merge'
export { getDefaultConfig } from './lib/default-config'
export { extendTailwindMerge } from './lib/extend-tailwind-merge'
export { fromTheme } from './lib/from-theme'
export { mergeConfigs } from './lib/merge-configs'
export { twJoin, type ClassNameValue } from './lib/tw-join'
export { twMerge } from './lib/tw-merge'
export type { Config } from './lib/types'
export * as validators from './lib/validators'
/**
* @deprecated Will be removed in next major version. Use `twJoin` instead.
*/
export const join = twJoin

203
node_modules/tailwind-merge/src/lib/class-utils.ts generated vendored Normal file
View File

@@ -0,0 +1,203 @@
import { ClassGroup, ClassGroupId, ClassValidator, Config, ThemeGetter, ThemeObject } from './types'
export interface ClassPartObject {
nextPart: Map<string, ClassPartObject>
validators: ClassValidatorObject[]
classGroupId?: ClassGroupId
}
interface ClassValidatorObject {
classGroupId: ClassGroupId
validator: ClassValidator
}
const CLASS_PART_SEPARATOR = '-'
export function createClassUtils(config: Config) {
const classMap = createClassMap(config)
const { conflictingClassGroups, conflictingClassGroupModifiers = {} } = config
function getClassGroupId(className: string) {
const classParts = className.split(CLASS_PART_SEPARATOR)
// Classes like `-inset-1` produce an empty string as first classPart. We assume that classes for negative values are used correctly and remove it from classParts.
if (classParts[0] === '' && classParts.length !== 1) {
classParts.shift()
}
return getGroupRecursive(classParts, classMap) || getGroupIdForArbitraryProperty(className)
}
function getConflictingClassGroupIds(classGroupId: ClassGroupId, hasPostfixModifier: boolean) {
const conflicts = conflictingClassGroups[classGroupId] || []
if (hasPostfixModifier && conflictingClassGroupModifiers[classGroupId]) {
return [...conflicts, ...conflictingClassGroupModifiers[classGroupId]!]
}
return conflicts
}
return {
getClassGroupId,
getConflictingClassGroupIds,
}
}
function getGroupRecursive(
classParts: string[],
classPartObject: ClassPartObject,
): ClassGroupId | undefined {
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)
: undefined
if (classGroupFromNextClassPart) {
return classGroupFromNextClassPart
}
if (classPartObject.validators.length === 0) {
return undefined
}
const classRest = classParts.join(CLASS_PART_SEPARATOR)
return classPartObject.validators.find(({ validator }) => validator(classRest))?.classGroupId
}
const arbitraryPropertyRegex = /^\[(.+)\]$/
function getGroupIdForArbitraryProperty(className: string) {
if (arbitraryPropertyRegex.test(className)) {
const arbitraryPropertyClassName = arbitraryPropertyRegex.exec(className)![1]
const property = arbitraryPropertyClassName?.substring(
0,
arbitraryPropertyClassName.indexOf(':'),
)
if (property) {
// I use two dots here because one dot is used as prefix for class groups in plugins
return 'arbitrary..' + property
}
}
}
/**
* Exported for testing only
*/
export function createClassMap(config: Config) {
const { theme, prefix } = config
const classMap: ClassPartObject = {
nextPart: new Map<string, ClassPartObject>(),
validators: [],
}
const prefixedClassGroupEntries = getPrefixedClassGroupEntries(
Object.entries(config.classGroups),
prefix,
)
prefixedClassGroupEntries.forEach(([classGroupId, classGroup]) => {
processClassesRecursively(classGroup, classMap, classGroupId, theme)
})
return classMap
}
function processClassesRecursively(
classGroup: ClassGroup,
classPartObject: ClassPartObject,
classGroupId: ClassGroupId,
theme: ThemeObject,
) {
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, classGroup]) => {
processClassesRecursively(
classGroup,
getPart(classPartObject, key),
classGroupId,
theme,
)
})
})
}
function getPart(classPartObject: ClassPartObject, path: string) {
let currentClassPartObject = classPartObject
path.split(CLASS_PART_SEPARATOR).forEach((pathPart) => {
if (!currentClassPartObject.nextPart.has(pathPart)) {
currentClassPartObject.nextPart.set(pathPart, {
nextPart: new Map(),
validators: [],
})
}
currentClassPartObject = currentClassPartObject.nextPart.get(pathPart)!
})
return currentClassPartObject
}
function isThemeGetter(func: ClassValidator | ThemeGetter): func is ThemeGetter {
return (func as ThemeGetter).isThemeGetter
}
function getPrefixedClassGroupEntries(
classGroupEntries: Array<[classGroupId: string, classGroup: ClassGroup]>,
prefix: string | undefined,
): Array<[classGroupId: string, classGroup: ClassGroup]> {
if (!prefix) {
return classGroupEntries
}
return classGroupEntries.map(([classGroupId, classGroup]) => {
const prefixedClassGroup = classGroup.map((classDefinition) => {
if (typeof classDefinition === 'string') {
return prefix + classDefinition
}
if (typeof classDefinition === 'object') {
return Object.fromEntries(
Object.entries(classDefinition).map(([key, value]) => [prefix + key, value]),
)
}
return classDefinition
})
return [classGroupId, prefixedClassGroup]
})
}

14
node_modules/tailwind-merge/src/lib/config-utils.ts generated vendored Normal file
View File

@@ -0,0 +1,14 @@
import { createClassUtils } from './class-utils'
import { createLruCache } from './lru-cache'
import { createSplitModifiers } from './modifier-utils'
import { Config } from './types'
export type ConfigUtils = ReturnType<typeof createConfigUtils>
export function createConfigUtils(config: Config) {
return {
cache: createLruCache<string, string>(config.cacheSize),
splitModifiers: createSplitModifiers(config),
...createClassUtils(config),
}
}

View File

@@ -0,0 +1,51 @@
import { createConfigUtils } from './config-utils'
import { mergeClassList } from './merge-classlist'
import { ClassNameValue, twJoin } from './tw-join'
import { Config } from './types'
type CreateConfigFirst = () => Config
type CreateConfigSubsequent = (config: Config) => Config
type TailwindMerge = (...classLists: ClassNameValue[]) => string
type ConfigUtils = ReturnType<typeof createConfigUtils>
export function createTailwindMerge(
...createConfig: [CreateConfigFirst, ...CreateConfigSubsequent[]]
): TailwindMerge {
let configUtils: ConfigUtils
let cacheGet: ConfigUtils['cache']['get']
let cacheSet: ConfigUtils['cache']['set']
let functionToCall = initTailwindMerge
function initTailwindMerge(classList: string) {
const [firstCreateConfig, ...restCreateConfig] = createConfig
const config = restCreateConfig.reduce(
(previousConfig, createConfigCurrent) => createConfigCurrent(previousConfig),
firstCreateConfig(),
)
configUtils = createConfigUtils(config)
cacheGet = configUtils.cache.get
cacheSet = configUtils.cache.set
functionToCall = tailwindMerge
return tailwindMerge(classList)
}
function tailwindMerge(classList: string) {
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 as any))
}
}

1783
node_modules/tailwind-merge/src/lib/default-config.ts generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
import { createTailwindMerge } from './create-tailwind-merge'
import { getDefaultConfig } from './default-config'
import { mergeConfigs } from './merge-configs'
import { Config } from './types'
type CreateConfigSubsequent = (config: Config) => Config
export function extendTailwindMerge(
configExtension: Partial<Config> | CreateConfigSubsequent,
...createConfig: CreateConfigSubsequent[]
) {
return typeof configExtension === 'function'
? createTailwindMerge(getDefaultConfig, configExtension, ...createConfig)
: createTailwindMerge(
() => mergeConfigs(getDefaultConfig(), configExtension),
...createConfig,
)
}

9
node_modules/tailwind-merge/src/lib/from-theme.ts generated vendored Normal file
View File

@@ -0,0 +1,9 @@
import { ThemeGetter, ThemeObject } from './types'
export function fromTheme(key: string): ThemeGetter {
const themeGetter = (theme: ThemeObject) => theme[key] || []
themeGetter.isThemeGetter = true as const
return themeGetter
}

52
node_modules/tailwind-merge/src/lib/lru-cache.ts generated vendored Normal file
View File

@@ -0,0 +1,52 @@
// Export is needed because TypeScript complains about an error otherwise:
// Error: …/tailwind-merge/src/config-utils.ts(8,17): semantic error TS4058: Return type of exported function has or is using name 'LruCache' from external module "…/tailwind-merge/src/lru-cache" but cannot be named.
export interface LruCache<Key, Value> {
get(key: Key): Value | undefined
set(key: Key, value: Value): void
}
// LRU cache inspired from hashlru (https://github.com/dominictarr/hashlru/blob/v1.0.4/index.js) but object replaced with Map to improve performance
export function createLruCache<Key, Value>(maxCacheSize: number): LruCache<Key, Value> {
if (maxCacheSize < 1) {
return {
get: () => undefined,
set: () => {},
}
}
let cacheSize = 0
let cache = new Map<Key, Value>()
let previousCache = new Map<Key, Value>()
function update(key: Key, value: Value) {
cache.set(key, value)
cacheSize++
if (cacheSize > maxCacheSize) {
cacheSize = 0
previousCache = cache
cache = new Map()
}
}
return {
get(key) {
let value = cache.get(key)
if (value !== undefined) {
return value
}
if ((value = previousCache.get(key)) !== undefined) {
update(key, value)
return value
}
},
set(key, value) {
if (cache.has(key)) {
cache.set(key, value)
} else {
update(key, value)
}
},
}
}

99
node_modules/tailwind-merge/src/lib/merge-classlist.ts generated vendored Normal file
View File

@@ -0,0 +1,99 @@
import { ConfigUtils } from './config-utils'
import { IMPORTANT_MODIFIER, sortModifiers } from './modifier-utils'
const SPLIT_CLASSES_REGEX = /\s+/
export function mergeClassList(classList: string, configUtils: ConfigUtils) {
const { splitModifiers, getClassGroupId, getConflictingClassGroupIds } = configUtils
/**
* Set of classGroupIds in following format:
* `{importantModifier}{variantModifiers}{classGroupId}`
* @example 'float'
* @example 'hover:focus:bg-color'
* @example 'md:!pr'
*/
const classGroupsInConflict = new Set<string>()
return (
classList
.trim()
.split(SPLIT_CLASSES_REGEX)
.map((originalClassName) => {
const {
modifiers,
hasImportantModifier,
baseClassName,
maybePostfixModifierPosition,
} = splitModifiers(originalClassName)
let classGroupId = getClassGroupId(
maybePostfixModifierPosition
? baseClassName.substring(0, maybePostfixModifierPosition)
: baseClassName,
)
let hasPostfixModifier = Boolean(maybePostfixModifierPosition)
if (!classGroupId) {
if (!maybePostfixModifierPosition) {
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(' ')
)
}

51
node_modules/tailwind-merge/src/lib/merge-configs.ts generated vendored Normal file
View File

@@ -0,0 +1,51 @@
import { Config } from './types'
/**
* @param baseConfig Config where other config will be merged into. This object will be mutated.
* @param configExtension Partial config to merge into the `baseConfig`.
*/
export function mergeConfigs(baseConfig: Config, configExtension: Partial<Config>) {
for (const key in configExtension) {
mergePropertyRecursively(baseConfig as any, key, configExtension[key as keyof Config])
}
return baseConfig
}
const hasOwnProperty = Object.prototype.hasOwnProperty
const overrideTypes = new Set(['string', 'number', 'boolean'])
function mergePropertyRecursively(
baseObject: Record<string, unknown>,
mergeKey: string,
mergeValue: unknown,
) {
if (
!hasOwnProperty.call(baseObject, mergeKey) ||
overrideTypes.has(typeof mergeValue) ||
mergeValue === null
) {
baseObject[mergeKey] = mergeValue
return
}
if (Array.isArray(mergeValue) && Array.isArray(baseObject[mergeKey])) {
baseObject[mergeKey] = (baseObject[mergeKey] as unknown[]).concat(mergeValue)
return
}
if (typeof mergeValue === 'object' && typeof baseObject[mergeKey] === 'object') {
if (baseObject[mergeKey] === null) {
baseObject[mergeKey] = mergeValue
return
}
for (const nextKey in mergeValue) {
mergePropertyRecursively(
baseObject[mergeKey] as Record<string, unknown>,
nextKey,
mergeValue[nextKey as keyof object],
)
}
}
}

95
node_modules/tailwind-merge/src/lib/modifier-utils.ts generated vendored Normal file
View File

@@ -0,0 +1,95 @@
import { Config } from './types'
export const IMPORTANT_MODIFIER = '!'
export function createSplitModifiers(config: Config) {
const separator = config.separator || ':'
const isSeparatorSingleCharacter = separator.length === 1
const firstSeparatorCharacter = separator[0]
const separatorLength = separator.length
// splitModifiers inspired by https://github.com/tailwindlabs/tailwindcss/blob/v3.2.2/src/util/splitAtTopLevelOnly.js
return function splitModifiers(className: string) {
const modifiers = []
let bracketDepth = 0
let modifierStart = 0
let postfixModifierPosition: number | undefined
for (let index = 0; index < className.length; index++) {
let currentCharacter = className[index]
if (bracketDepth === 0) {
if (
currentCharacter === firstSeparatorCharacter &&
(isSeparatorSingleCharacter ||
className.slice(index, index + separatorLength) === separator)
) {
modifiers.push(className.slice(modifierStart, index))
modifierStart = index + separatorLength
continue
}
if (currentCharacter === '/') {
postfixModifierPosition = index
continue
}
}
if (currentCharacter === '[') {
bracketDepth++
} else if (currentCharacter === ']') {
bracketDepth--
}
}
const baseClassNameWithImportantModifier =
modifiers.length === 0 ? className : className.substring(modifierStart)
const hasImportantModifier =
baseClassNameWithImportantModifier.startsWith(IMPORTANT_MODIFIER)
const baseClassName = hasImportantModifier
? baseClassNameWithImportantModifier.substring(1)
: baseClassNameWithImportantModifier
const maybePostfixModifierPosition =
postfixModifierPosition && postfixModifierPosition > modifierStart
? postfixModifierPosition - modifierStart
: undefined
return {
modifiers,
hasImportantModifier,
baseClassName,
maybePostfixModifierPosition,
}
}
}
/**
* Sorts modifiers according to following schema:
* - Predefined modifiers are sorted alphabetically
* - When an arbitrary variant appears, it must be preserved which modifiers are before and after it
*/
export function sortModifiers(modifiers: string[]) {
if (modifiers.length <= 1) {
return modifiers
}
const sortedModifiers: string[] = []
let unsortedModifiers: string[] = []
modifiers.forEach((modifier) => {
const isArbitraryVariant = modifier[0] === '['
if (isArbitraryVariant) {
sortedModifiers.push(...unsortedModifiers.sort(), modifier)
unsortedModifiers = []
} else {
unsortedModifiers.push(modifier)
}
})
sortedModifiers.push(...unsortedModifiers.sort())
return sortedModifiers
}

50
node_modules/tailwind-merge/src/lib/tw-join.ts generated vendored Normal file
View File

@@ -0,0 +1,50 @@
/**
* The code in this file is copied from https://github.com/lukeed/clsx and modified to suit the needs of tailwind-merge better.
*
* Specifically:
* - Runtime code from https://github.com/lukeed/clsx/blob/v1.2.1/src/index.js
* - TypeScript types from https://github.com/lukeed/clsx/blob/v1.2.1/clsx.d.ts
*
* Original code has MIT license: Copyright (c) Luke Edwards <luke.edwards05@gmail.com> (lukeed.com)
*/
export type ClassNameValue = ClassNameArray | string | null | undefined | 0 | false
type ClassNameArray = ClassNameValue[]
export function twJoin(...classLists: ClassNameValue[]): string
export function twJoin() {
let index = 0
let argument: ClassNameValue
let resolvedValue: string
let string = ''
while (index < arguments.length) {
if ((argument = arguments[index++])) {
if ((resolvedValue = toValue(argument))) {
string && (string += ' ')
string += resolvedValue
}
}
}
return string
}
function toValue(mix: ClassNameArray | string) {
if (typeof mix === 'string') {
return mix
}
let resolvedValue: string
let string = ''
for (let k = 0; k < mix.length; k++) {
if (mix[k]) {
if ((resolvedValue = toValue(mix[k] as ClassNameArray | string))) {
string && (string += ' ')
string += resolvedValue
}
}
}
return string
}

4
node_modules/tailwind-merge/src/lib/tw-merge.ts generated vendored Normal file
View File

@@ -0,0 +1,4 @@
import { createTailwindMerge } from './create-tailwind-merge'
import { getDefaultConfig } from './default-config'
export const twMerge = createTailwindMerge(getDefaultConfig)

58
node_modules/tailwind-merge/src/lib/types.ts generated vendored Normal file
View File

@@ -0,0 +1,58 @@
export interface Config {
/**
* Integer indicating size of LRU cache used for memoizing results.
* - Cache might be up to twice as big as `cacheSize`
* - No cache is used for values <= 0
*/
cacheSize: number
/**
* Prefix added to Tailwind-generated classes
* @see https://tailwindcss.com/docs/configuration#prefix
*/
prefix?: string
/**
* Custom separator for modifiers in Tailwind classes
* @see https://tailwindcss.com/docs/configuration#separator
*/
separator?: string
/**
* Theme scales used in classGroups.
* The keys are the same as in the Tailwind config but the values are sometimes defined more broadly.
*/
theme: ThemeObject
/**
* Object with groups of classes.
* @example
* {
* // Creates group of classes `group`, `of` and `classes`
* 'group-id': ['group', 'of', 'classes'],
* // Creates group of classes `look-at-me-other` and `look-at-me-group`.
* 'other-group': [{ 'look-at-me': ['other', 'group']}]
* }
*/
classGroups: Record<ClassGroupId, ClassGroup>
/**
* Conflicting classes across groups.
* The key is ID of class group which creates conflict, values are IDs of class groups which receive a conflict.
* A class group ID is the key of a class group in classGroups object.
* @example { gap: ['gap-x', 'gap-y'] }
*/
conflictingClassGroups: Record<ClassGroupId, readonly ClassGroupId[]>
/**
* Postfix modifiers conflicting with other class groups.
* A class group ID is the key of a class group in classGroups object.
* @example { 'font-size': ['leading'] }
*/
conflictingClassGroupModifiers?: Record<ClassGroupId, readonly ClassGroupId[]>
}
export type ThemeObject = Record<string, ClassGroup>
export type ClassGroupId = string
export type ClassGroup = readonly ClassDefinition[]
type ClassDefinition = string | ClassValidator | ThemeGetter | ClassObject
export type ClassValidator = (classPart: string) => boolean
export interface ThemeGetter {
(theme: ThemeObject): ClassGroup
isThemeGetter: true
}
type ClassObject = Record<string, readonly ClassDefinition[]>

104
node_modules/tailwind-merge/src/lib/validators.ts generated vendored Normal file
View File

@@ -0,0 +1,104 @@
const arbitraryValueRegex = /^\[(?:([a-z-]+):)?(.+)\]$/i
const fractionRegex = /^\d+\/\d+$/
const stringLengths = new Set(['px', 'full', 'screen'])
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$/
// Shadow always begins with x and y offset separated by underscore
const shadowRegex = /^-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/
export function isLength(value: string) {
return (
isNumber(value) ||
stringLengths.has(value) ||
fractionRegex.test(value) ||
isArbitraryLength(value)
)
}
export function isArbitraryLength(value: string) {
return getIsArbitraryValue(value, 'length', isLengthOnly)
}
export function isArbitrarySize(value: string) {
return getIsArbitraryValue(value, 'size', isNever)
}
export function isArbitraryPosition(value: string) {
return getIsArbitraryValue(value, 'position', isNever)
}
export function isArbitraryUrl(value: string) {
return getIsArbitraryValue(value, 'url', isUrl)
}
export function isArbitraryNumber(value: string) {
return getIsArbitraryValue(value, 'number', isNumber)
}
/**
* @deprecated Will be removed in next major version. Use `isArbitraryNumber` instead.
*/
export const isArbitraryWeight = isArbitraryNumber
export function isNumber(value: string) {
return !Number.isNaN(Number(value))
}
export function isPercent(value: string) {
return value.endsWith('%') && isNumber(value.slice(0, -1))
}
export function isInteger(value: string) {
return isIntegerOnly(value) || getIsArbitraryValue(value, 'number', isIntegerOnly)
}
export function isArbitraryValue(value: string) {
return arbitraryValueRegex.test(value)
}
export function isAny() {
return true
}
export function isTshirtSize(value: string) {
return tshirtUnitRegex.test(value)
}
export function isArbitraryShadow(value: string) {
return getIsArbitraryValue(value, '', isShadow)
}
function getIsArbitraryValue(value: string, label: string, testValue: (value: string) => boolean) {
const result = arbitraryValueRegex.exec(value)
if (result) {
if (result[1]) {
return result[1] === label
}
return testValue(result[2]!)
}
return false
}
function isLengthOnly(value: string) {
return lengthUnitRegex.test(value)
}
function isNever() {
return false
}
function isUrl(value: string) {
return value.startsWith('url(')
}
function isIntegerOnly(value: string) {
return Number.isInteger(Number(value))
}
function isShadow(value: string) {
return shadowRegex.test(value)
}