first commit
This commit is contained in:
16
node_modules/tailwind-merge/src/index.ts
generated
vendored
Normal file
16
node_modules/tailwind-merge/src/index.ts
generated
vendored
Normal 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
203
node_modules/tailwind-merge/src/lib/class-utils.ts
generated
vendored
Normal 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
14
node_modules/tailwind-merge/src/lib/config-utils.ts
generated
vendored
Normal 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),
|
||||
}
|
||||
}
|
||||
51
node_modules/tailwind-merge/src/lib/create-tailwind-merge.ts
generated
vendored
Normal file
51
node_modules/tailwind-merge/src/lib/create-tailwind-merge.ts
generated
vendored
Normal 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
1783
node_modules/tailwind-merge/src/lib/default-config.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
18
node_modules/tailwind-merge/src/lib/extend-tailwind-merge.ts
generated
vendored
Normal file
18
node_modules/tailwind-merge/src/lib/extend-tailwind-merge.ts
generated
vendored
Normal 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
9
node_modules/tailwind-merge/src/lib/from-theme.ts
generated
vendored
Normal 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
52
node_modules/tailwind-merge/src/lib/lru-cache.ts
generated
vendored
Normal 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
99
node_modules/tailwind-merge/src/lib/merge-classlist.ts
generated
vendored
Normal 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
51
node_modules/tailwind-merge/src/lib/merge-configs.ts
generated
vendored
Normal 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
95
node_modules/tailwind-merge/src/lib/modifier-utils.ts
generated
vendored
Normal 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
50
node_modules/tailwind-merge/src/lib/tw-join.ts
generated
vendored
Normal 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
4
node_modules/tailwind-merge/src/lib/tw-merge.ts
generated
vendored
Normal 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
58
node_modules/tailwind-merge/src/lib/types.ts
generated
vendored
Normal 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
104
node_modules/tailwind-merge/src/lib/validators.ts
generated
vendored
Normal 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)
|
||||
}
|
||||
Reference in New Issue
Block a user