From 9fa92781fab21715cfc915ec8f7929696e2a375e Mon Sep 17 00:00:00 2001 From: "Garen J. Torikian" Date: Mon, 3 Apr 2023 14:39:13 -0400 Subject: [PATCH 1/3] Add postfix support --- README.md | 6 ++++++ lib/tailwind_merge.rb | 28 +++++++++++++++++++++++++--- lib/tailwind_merge/class_utils.rb | 10 ++++++++-- lib/tailwind_merge/config.rb | 3 +++ lib/tailwind_merge/modifier_utils.rb | 18 +++++++++++++----- test/test_modifiers.rb | 9 ++++++++- test/test_tailwind_css_versions.rb | 2 ++ 7 files changed, 65 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 7196a9c..afd42c6 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/lib/tailwind_merge.rb b/lib/tailwind_merge.rb index c3fb626..4a0602e 100644 --- a/lib/tailwind_merge.rb +++ b/lib/tailwind_merge.rb @@ -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, @@ -69,6 +89,7 @@ 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| @@ -76,6 +97,7 @@ def merge(classes) 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}" @@ -83,7 +105,7 @@ def merge(classes) 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 diff --git a/lib/tailwind_merge/class_utils.rb b/lib/tailwind_merge/class_utils.rb index 9063796..25216b5 100644 --- a/lib/tailwind_merge/class_utils.rb +++ b/lib/tailwind_merge/class_utils.rb @@ -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) diff --git a/lib/tailwind_merge/config.rb b/lib/tailwind_merge/config.rb index aa96d37..346b7a3 100644 --- a/lib/tailwind_merge/config.rb +++ b/lib/tailwind_merge/config.rb @@ -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) diff --git a/lib/tailwind_merge/modifier_utils.rb b/lib/tailwind_merge/modifier_utils.rb index ac0fd6d..1ed02d4 100644 --- a/lib/tailwind_merge/modifier_utils.rb +++ b/lib/tailwind_merge/modifier_utils.rb @@ -7,22 +7,29 @@ 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 @@ -30,8 +37,9 @@ def split_modifiers(class_name, separator: nil) 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: diff --git a/test/test_modifiers.rb b/test/test_modifiers.rb index 2fee459..51a78e6 100644 --- a/test/test_modifiers.rb +++ b/test/test_modifiers.rb @@ -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 diff --git a/test/test_tailwind_css_versions.rb b/test/test_tailwind_css_versions.rb index 911ce51..4cee66b 100644 --- a/test/test_tailwind_css_versions.rb +++ b/test/test_tailwind_css_versions.rb @@ -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")) From 35173d4fb0f498830f7a339ebb278e622e3a0d05 Mon Sep 17 00:00:00 2001 From: "Garen J. Torikian" Date: Mon, 3 Apr 2023 14:39:39 -0400 Subject: [PATCH 2/3] lint --- lib/tailwind_merge/validators.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/tailwind_merge/validators.rb b/lib/tailwind_merge/validators.rb index fa8ade9..4317e8d 100644 --- a/lib/tailwind_merge/validators.rb +++ b/lib/tailwind_merge/validators.rb @@ -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) } From 3d05e7183aa852cdfcc9ad7764b79a7d1de14d70 Mon Sep 17 00:00:00 2001 From: "Garen J. Torikian" Date: Mon, 3 Apr 2023 14:39:54 -0400 Subject: [PATCH 3/3] :gem: 0.7.0 --- lib/tailwind_merge/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tailwind_merge/version.rb b/lib/tailwind_merge/version.rb index 797f02b..39f3c23 100644 --- a/lib/tailwind_merge/version.rb +++ b/lib/tailwind_merge/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module TailwindMerge - VERSION = "0.6.0" + VERSION = "0.7.0" end