Skip to content

Commit

Permalink
Merge pull request #10 from gjtorikian/add-postfix-support
Browse files Browse the repository at this point in the history
Add postfix support
  • Loading branch information
gjtorikian authored Apr 3, 2023
2 parents c4b7971 + 3d05e71 commit c1095a7
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 15 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ Similarly to arbitrary properties, `tailwind_merge` does not resolve conflicts b
@merger.merge('!right-2 !-inset-x-1') # → '!-inset-x-1'
```

## Supports postfix modifiers

```ts
twMerge('text-sm leading-6 text-lg/7') // → 'text-lg/7'
```

### Preserves non-Tailwind classes

```ruby
Expand Down
28 changes: 25 additions & 3 deletions lib/tailwind_merge.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,31 @@ def merge(classes)
class_groups_in_conflict = Set.new

classes.strip.split(SPLIT_CLASSES_REGEX).map do |original_class_name|
modifiers, has_important_modifier, base_class_name = split_modifiers(original_class_name, separator: @config[:separator])
modifiers, has_important_modifier, base_class_name, maybe_postfix_modifier_position = split_modifiers(original_class_name, separator: @config[:separator])

class_group_id = @class_utils.class_group_id(base_class_name)
actual_base_class_name = maybe_postfix_modifier_position ? base_class_name[0...maybe_postfix_modifier_position] : base_class_name
class_group_id = @class_utils.class_group_id(actual_base_class_name)

unless class_group_id
unless maybe_postfix_modifier_position
next {
is_tailwind_class: false,
original_class_name: original_class_name,
}
end

class_group_id = @class_utils.class_group_id(base_class_name)

unless class_group_id
next {
isTailwindClass: false,
original_class_name: original_class_name,
}

end

has_postfix_modifier = false

next {
is_tailwind_class: false,
original_class_name: original_class_name,
Expand All @@ -69,21 +89,23 @@ def merge(classes)
modifier_id: modifier_id,
class_group_id: class_group_id,
original_class_name: original_class_name,
has_postfix_modifier: has_postfix_modifier,
}
end.reverse # Last class in conflict wins, so filter conflicting classes in reverse order.
.select do |parsed|
next(true) unless parsed[:is_tailwind_class]

modifier_id = parsed[:modifier_id]
class_group_id = parsed[:class_group_id]
has_postfix_modifier = parsed[:has_postfix_modifier]

class_id = "#{modifier_id}#{class_group_id}"

next if class_groups_in_conflict.include?(class_id)

class_groups_in_conflict.add(class_id)

@class_utils.get_conflicting_class_group_ids(class_group_id).each do |group|
@class_utils.get_conflicting_class_group_ids(class_group_id, has_postfix_modifier).each do |group|
class_groups_in_conflict.add("#{modifier_id}#{group}")
end

Expand Down
10 changes: 8 additions & 2 deletions lib/tailwind_merge/class_utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,14 @@ def get_group_recursive(class_parts, class_part_object)
result.nil? ? result : result[:class_group_id]
end

def get_conflicting_class_group_ids(class_group_id)
@config[:conflicting_class_groups][class_group_id] || []
def get_conflicting_class_group_ids(class_group_id, has_postfix_modifier)
conflicts = @config[:conflicting_class_groups][class_group_id] || []

if has_postfix_modifier && @config[:conflicting_class_group_modifiers][class_group_id]
return [...conflicts, ...@config[:conflicting_class_group_modifiers][class_group_id]]
end

conflicts
end

private def create_class_map(config)
Expand Down
3 changes: 3 additions & 0 deletions lib/tailwind_merge/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1782,6 +1782,9 @@ module Config
"scroll-px" => ["scroll-pr", "scroll-pl"],
"scroll-py" => ["scroll-pt", "scroll-pb"],
},
conflicting_class_group_modifiers: {
"font-size": ["leading"],
},
}.freeze

def merge_configs(extension_config)
Expand Down
18 changes: 13 additions & 5 deletions lib/tailwind_merge/modifier_utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,39 @@ module ModifierUtils
def split_modifiers(class_name, separator: nil)
separator ||= ":"
separator_length = separator.length
seperator_is_single_char = separator_length == 1
first_seperator_char = separator[0]

modifiers = []
bracket_depth = 0
modifier_start = 0
postfix_modifier_position = 0

class_name.each_char.with_index do |char, index|
if bracket_depth.zero? && char == separator[0]
if separator_length == 1 || class_name[index..(index + separator_length - 1)] == separator
if bracket_depth.zero?
if char == first_seperator_char && (seperator_is_single_char || class_name[index..(index + separator_length - 1)] == separator)
modifiers << class_name[modifier_start..index]
modifier_start = index + separator_length
next
elsif char == "/"
postfix_modifier_position = index
next
end
end

if class_name[index] == "["
if char == "["
bracket_depth += 1
elsif class_name[index] == "]"
elsif char == "]"
bracket_depth -= 1
end
end

base_class_name_with_important_modifier = modifiers.empty? ? class_name : class_name[modifier_start..-1]
has_important_modifier = base_class_name_with_important_modifier.start_with?(IMPORTANT_MODIFIER)
base_class_name = has_important_modifier ? base_class_name_with_important_modifier[1..-1] : base_class_name_with_important_modifier
maybe_postfix_modifier_position = postfix_modifier_position && postfix_modifier_position > modifier_start ? postfix_modifier_position - modifier_start : false

[modifiers, has_important_modifier, base_class_name]
[modifiers, has_important_modifier, base_class_name, maybe_postfix_modifier_position]
end

# Sorts modifiers according to following schema:
Expand Down
6 changes: 3 additions & 3 deletions lib/tailwind_merge/validators.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ def integer?(x)
}

IS_LENGTH = ->(value) {
numeric?(value) || \
STRING_LENGTHS.include?(value) || \
FRACTION_REGEX.match?(value) || \
numeric?(value) ||
STRING_LENGTHS.include?(value) ||
FRACTION_REGEX.match?(value) ||
IS_ARBITRARY_LENGTH.call(value)
}

Expand Down
2 changes: 1 addition & 1 deletion lib/tailwind_merge/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module TailwindMerge
VERSION = "0.6.0"
VERSION = "0.7.0"
end
9 changes: 8 additions & 1 deletion test/test_modifiers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,17 @@ def setup
@merger = TailwindMerge::Merger.new
end

def test_conflicts_across_modifiers
def test_conflicts_across_prefix_modifiers
assert_equal("hover:inline", @merger.merge("hover:block hover:inline"))
assert_equal("hover:block hover:focus:inline", @merger.merge("hover:block hover:focus:inline"))
assert_equal("hover:block focus:hover:inline", @merger.merge("hover:block hover:focus:inline focus:hover:inline"))
assert_equal("focus-within:block", @merger.merge("focus-within:inline focus-within:block"))
end

def test_conflicts_across_postfix_modifiers
assert_equal("text-lg/8", @merger.merge("text-lg/7 text-lg/8"))
assert_equal("text-lg/none leading-9", @merger.merge("text-lg/none leading-9"))
assert_equal("text-lg/none", @merger.merge("leading-9 text-lg/none"))
assert_equal("w-1/2", @merger.merge("w-full w-1/2"))
end
end
2 changes: 2 additions & 0 deletions test/test_tailwind_css_versions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ def setup
end

def test_tailwind_3_3_features
assert_equal("text-red text-lg/8", @merger.merge("text-red text-lg/7 text-lg/8"))

assert_equal("start-1 end-1 ps-1 pe-1 ms-1 me-1 rounded-s-md rounded-e-md rounded-ss-md rounded-ee-md", @merger.merge("start-0 start-1 end-0 end-1 ps-0 ps-1 pe-0 pe-1 ms-0 ms-1 me-0 me-1 rounded-s-sm rounded-s-md rounded-e-sm rounded-e-md rounded-ss-sm rounded-ss-md rounded-ee-sm rounded-ee-md"))

assert_equal("inset-0 p-0 m-0 rounded-s", @merger.merge("start-0 end-0 inset-0 ps-0 pe-0 p-0 ms-0 me-0 m-0 rounded-ss rounded-es rounded-s"))
Expand Down

0 comments on commit c1095a7

Please sign in to comment.