Module: TailwindMerge::Validators

Included in:
Config
Defined in:
lib/tailwind_merge/validators.rb

Constant Summary collapse

ARBITRARY_VALUE_REGEX =
/^\[(?:(\w[\w-]*):)?(.+)\]$/i
ARBITRARY_VARIABLE_REGEX =
/^\((?:(\w[\w-]*):)?(.+)\)$/i
FRACTION_REGEX =
%r{^\d+/\d+$}
TSHIRT_UNIT_REGEX =
/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/
LENGTH_UNIT_REGEX =
/\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$/
COLOR_FUNCTION_REGEX =
/^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/
SHADOW_REGEX =

Shadow always begins with x and y offset separated by underscore optionally prepended by inset

/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/
IMAGE_REGEX =
/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/
IS_FRACTION =
->(value) {
  FRACTION_REGEX.match?(value)
}
IS_NUMBER =
->(value) {
  numeric?(value)
}
IS_INTEGER =
->(value) {
  integer?(value)
}
IS_PERCENT =
->(value) {
  value.end_with?("%") && IS_NUMBER.call(value[0..-2])
}
IS_TSHIRT_SIZE =
->(value) {
  TSHIRT_UNIT_REGEX.match?(value)
}
IS_ANY =
->(_ = nil) { true }
IS_LENGTH_ONLY =
->(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.
  LENGTH_UNIT_REGEX.match?(value) && !COLOR_FUNCTION_REGEX.match?(value)
}
IS_NEVER =
->(_) { false }
IS_SHADOW =
->(value) {
  SHADOW_REGEX.match?(value)
}
IS_IMAGE =
->(value) {
  IMAGE_REGEX.match?(value)
}
IS_ANY_NON_ARBITRARY =
->(value) {
  !IS_ARBITRARY_VALUE.call(value) && !IS_ARBITRARY_VARIABLE.call(value)
}
IS_ARBITRARY_SIZE =
->(value) {
  arbitrary_value?(value, IS_LABEL_SIZE, IS_NEVER)
}
IS_ARBITRARY_VALUE =
->(value) {
  ARBITRARY_VALUE_REGEX.match(value)
}
IS_ARBITRARY_LENGTH =
->(value) {
  arbitrary_value?(value, IS_LABEL_LENGTH, IS_LENGTH_ONLY)
}
IS_ARBITRARY_NUMBER =
->(value) {
  arbitrary_value?(value, IS_LABEL_NUMBER, IS_NUMBER)
}
IS_ARBITRARY_POSITION =
->(value) {
  arbitrary_value?(value, IS_LABEL_POSITION, IS_NEVER)
}
IS_ARBITRARY_IMAGE =
->(value) {
  arbitrary_value?(value, IS_LABEL_IMAGE, IS_IMAGE)
}
IS_ARBITRARY_SHADOW =
->(value) {
  arbitrary_value?(value, IS_LABEL_SHADOW, IS_SHADOW)
}
IS_ARBITRARY_VARIABLE =
->(value) {
  ARBITRARY_VARIABLE_REGEX.match(value)
}
IS_ARBITRARY_VARIABLE_LENGTH =
->(value) {
  arbitrary_variable?(value, IS_LABEL_LENGTH)
}
IS_ARBITRARY_VARIABLE_FAMILY_NAME =
->(value) {
  arbitrary_variable?(value, IS_LABEL_FAMILY_NAME)
}
IS_ARBITRARY_VARIABLE_POSITION =
->(value) {
  arbitrary_variable?(value, IS_LABEL_POSITION)
}
IS_ARBITRARY_VARIABLE_SIZE =
->(value) {
  arbitrary_variable?(value, IS_LABEL_SIZE)
}
IS_ARBITRARY_VARIABLE_IMAGE =
->(value) {
  arbitrary_variable?(value, IS_LABEL_IMAGE)
}
IS_ARBITRARY_VARIABLE_SHADOW =
->(value) {
  arbitrary_variable?(value, IS_LABEL_SHADOW, should_match_no_label: true)
}
IS_LABEL_POSITION =

Labels

->(label) {
  label == "position" || label == "percentage"
}
IS_LABEL_IMAGE =
->(label) {
  label == "image" || label == "url"
}
IS_LABEL_SIZE =
->(label) {
  label == "length" || label == "size" || label == "bg-size"
}
IS_LABEL_LENGTH =
->(label) {
  label == "length"
}
IS_LABEL_NUMBER =
->(label) {
  label == "number"
}
IS_LABEL_FAMILY_NAME =
->(label) {
  label == "family-name"
}
IS_LABEL_SHADOW =
->(label) {
  label == "shadow"
}

Class Method Summary collapse

Class Method Details

.arbitrary_value?(class_part, test_label, test_value) ⇒ Boolean

Returns:

  • (Boolean)


8
9
10
11
12
13
14
15
# File 'lib/tailwind_merge/validators.rb', line 8

def arbitrary_value?(class_part, test_label, test_value)
  match = ARBITRARY_VALUE_REGEX.match(class_part)
  return false unless match

  return test_label.call(match[1]) unless match[1].nil?

  test_value.call(match[2])
end

.arbitrary_variable?(class_part, test_label, should_match_no_label: false) ⇒ Boolean

Returns:

  • (Boolean)


17
18
19
20
21
22
23
24
# File 'lib/tailwind_merge/validators.rb', line 17

def arbitrary_variable?(class_part, test_label, should_match_no_label: false)
  match = ARBITRARY_VARIABLE_REGEX.match(class_part)
  return false unless match

  return test_label.call(match[1]) unless match[1].nil?

  should_match_no_label
end

.integer?(x) ⇒ Boolean

Returns:

  • (Boolean)


30
31
32
# File 'lib/tailwind_merge/validators.rb', line 30

def integer?(x)
  Integer(x, exception: false).is_a?(Integer)
end

.numeric?(x) ⇒ Boolean

Returns:

  • (Boolean)


26
27
28
# File 'lib/tailwind_merge/validators.rb', line 26

def numeric?(x)
  Float(x, exception: false).is_a?(Numeric)
end