primer_view_components 0.0.60 → 0.0.64

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +155 -1
  3. data/app/components/primer/alpha/border_box/header.rb +1 -2
  4. data/app/components/primer/alpha/button_marketing.rb +4 -4
  5. data/app/components/primer/alpha/layout.html.erb +5 -0
  6. data/app/components/primer/alpha/layout.rb +276 -0
  7. data/app/components/primer/alpha/tab_nav.rb +1 -1
  8. data/app/components/primer/alpha/tab_panels.rb +2 -2
  9. data/app/components/primer/alpha/underline_nav.rb +2 -1
  10. data/app/components/primer/alpha/underline_panels.rb +2 -2
  11. data/app/components/primer/base_button.rb +1 -5
  12. data/app/components/primer/base_component.rb +14 -37
  13. data/app/components/primer/beta/auto_complete/item.rb +1 -1
  14. data/app/components/primer/beta/auto_complete.rb +4 -2
  15. data/app/components/primer/beta/avatar.rb +1 -1
  16. data/app/components/primer/beta/blankslate.html.erb +15 -0
  17. data/app/components/primer/beta/blankslate.rb +241 -0
  18. data/app/components/primer/beta/breadcrumbs.rb +2 -2
  19. data/app/components/primer/beta/text.rb +1 -1
  20. data/app/components/primer/blankslate_component.rb +1 -1
  21. data/app/components/primer/border_box_component.rb +1 -1
  22. data/app/components/primer/box_component.rb +3 -2
  23. data/app/components/primer/button_component.html.erb +3 -9
  24. data/app/components/primer/button_component.rb +50 -19
  25. data/app/components/primer/button_group.rb +1 -8
  26. data/app/components/primer/clipboard_copy.rb +1 -1
  27. data/app/components/primer/close_button.rb +1 -1
  28. data/app/components/primer/component.rb +79 -2
  29. data/app/components/primer/counter_component.rb +1 -1
  30. data/app/components/primer/details_component.rb +1 -1
  31. data/app/components/primer/dropdown/menu.rb +1 -1
  32. data/app/components/primer/dropdown.html.erb +0 -1
  33. data/app/components/primer/dropdown.rb +1 -0
  34. data/app/components/primer/dropdown_menu_component.rb +1 -1
  35. data/app/components/primer/flash_component.rb +2 -1
  36. data/app/components/primer/flex_component.rb +16 -16
  37. data/app/components/primer/flex_item_component.rb +1 -1
  38. data/app/components/primer/hellip_button.rb +39 -0
  39. data/app/components/primer/hidden_text_expander.rb +19 -7
  40. data/app/components/primer/image.rb +1 -1
  41. data/app/components/primer/image_crop.rb +2 -1
  42. data/app/components/primer/layout_component.rb +1 -0
  43. data/app/components/primer/local_time.rb +1 -1
  44. data/app/components/primer/markdown.rb +1 -1
  45. data/app/components/primer/menu_component.rb +2 -1
  46. data/app/components/primer/navigation/tab_component.rb +1 -0
  47. data/app/components/primer/octicon_component.rb +4 -2
  48. data/app/components/primer/octicon_symbols_component.rb +2 -2
  49. data/app/components/primer/popover_component.rb +3 -3
  50. data/app/components/primer/progress_bar_component.rb +7 -6
  51. data/app/components/primer/spinner_component.html.erb +11 -3
  52. data/app/components/primer/spinner_component.rb +6 -7
  53. data/app/components/primer/subhead_component.rb +4 -2
  54. data/app/components/primer/tab_container_component.rb +1 -1
  55. data/app/components/primer/time_ago_component.rb +1 -1
  56. data/app/components/primer/timeline_item_component.rb +4 -3
  57. data/app/components/primer/tooltip.rb +1 -0
  58. data/app/lib/primer/octicon/cache.rb +4 -10
  59. data/lib/primer/classify/utilities.rb +26 -23
  60. data/lib/primer/classify/utilities.yml +298 -68
  61. data/lib/primer/classify.rb +94 -180
  62. data/lib/primer/view_components/engine.rb +2 -1
  63. data/lib/primer/view_components/linters/base_linter.rb +3 -52
  64. data/lib/primer/view_components/linters/blankslate_api_migration.rb +152 -0
  65. data/lib/primer/view_components/linters/blankslate_component_migration_counter.rb +1 -1
  66. data/lib/primer/view_components/linters/close_button_component_migration_counter.rb +2 -4
  67. data/lib/primer/view_components/linters/helpers/rubocop_helpers.rb +14 -0
  68. data/lib/primer/view_components/linters/tag_tree_helpers.rb +61 -0
  69. data/lib/primer/view_components/linters/two_column_layout_migration_counter.rb +158 -0
  70. data/lib/primer/view_components/version.rb +1 -1
  71. data/lib/rubocop/cop/primer/deprecated_layout_component.rb +30 -0
  72. data/lib/rubocop/cop/primer/primer_octicon.rb +1 -3
  73. data/lib/tasks/custom_utilities.yml +298 -0
  74. data/lib/tasks/docs.rake +50 -1
  75. data/lib/tasks/utilities.rake +6 -2
  76. data/static/arguments.yml +56 -71
  77. data/static/audited_at.json +5 -0
  78. data/static/classes.yml +35 -17
  79. data/static/constants.json +108 -7
  80. data/static/statuses.json +6 -1
  81. metadata +18 -13
  82. data/app/components/primer/auto_complete/auto_complete.d.ts +0 -1
  83. data/app/components/primer/auto_complete/auto_complete.js +0 -1
  84. data/app/components/primer/auto_complete/auto_component.d.ts +0 -1
  85. data/app/components/primer/auto_complete/auto_component.js +0 -1
  86. data/lib/primer/classify/cache.rb +0 -109
  87. data/lib/primer/classify/flex.rb +0 -111
@@ -4,6 +4,8 @@ require "json"
4
4
  require "openssl"
5
5
  require "primer/view_components/constants"
6
6
 
7
+ require_relative "tag_tree_helpers"
8
+
7
9
  # :nocov:
8
10
 
9
11
  module ERBLint
@@ -14,11 +16,7 @@ module ERBLint
14
16
  # * `CLASSES` - optional - The CSS classes that the component needs. The linter will only match elements with one of those classes.
15
17
  # * `REQUIRED_ARGUMENTS` - optional - A list of HTML attributes that are required by the component.
16
18
  class BaseLinter < Linter
17
- # from https://github.com/Shopify/erb-lint/blob/6179ee2d9d681a6ec4dd02351a1e30eefa748d3d/lib/erb_lint/linters/self_closing_tag.rb
18
- SELF_CLOSING_TAGS = %w[
19
- area base br col command embed hr input keygen
20
- link menuitem meta param source track wbr img
21
- ].freeze
19
+ include TagTreeHelpers
22
20
 
23
21
  DUMP_FILE = ".erblint-counter-ignore.json"
24
22
  DISALLOWED_CLASSES = [].freeze
@@ -136,53 +134,6 @@ module ERBLint
136
134
  end
137
135
  end
138
136
 
139
- # This assumes that the AST provided represents valid HTML, where each tag has a corresponding closing tag.
140
- # From the tags, we build a structured tree which represents the tag hierarchy.
141
- # With this, we are able to know where the tags start and end.
142
- def build_tag_tree(processed_source)
143
- nodes = processed_source.ast.children
144
- tag_tree = {}
145
- tags = []
146
- current_opened_tag = nil
147
-
148
- nodes.each do |node|
149
- if node.type == :tag
150
- # get the tag from previously calculated list so the references are the same
151
- tag = BetterHtml::Tree::Tag.from_node(node)
152
- tags << tag
153
-
154
- if tag.closing?
155
- if current_opened_tag && tag.name == current_opened_tag.name
156
- tag_tree[current_opened_tag][:closing] = tag
157
- current_opened_tag = tag_tree[current_opened_tag][:parent]
158
- end
159
-
160
- next
161
- end
162
-
163
- self_closing = self_closing?(tag)
164
-
165
- tag_tree[tag] = {
166
- tag: tag,
167
- closing: self_closing ? tag : nil,
168
- parent: current_opened_tag,
169
- children: []
170
- }
171
-
172
- tag_tree[current_opened_tag][:children] << tag_tree[tag] if current_opened_tag
173
- current_opened_tag = tag unless self_closing
174
- elsif current_opened_tag
175
- tag_tree[current_opened_tag][:children] << node
176
- end
177
- end
178
-
179
- [tags, tag_tree]
180
- end
181
-
182
- def self_closing?(tag)
183
- tag.self_closing? || SELF_CLOSING_TAGS.include?(tag.name)
184
- end
185
-
186
137
  def tags(processed_source)
187
138
  processed_source.parser.nodes_with_type(:tag).map { |tag_node| BetterHtml::Tree::Tag.from_node(tag_node) }
188
139
  end
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/string/indent"
4
+ require_relative "helpers/rubocop_helpers"
5
+
6
+ module ERBLint
7
+ module Linters
8
+ # Migrates from `Primer::BlankslateComponent` to `Primer::Beta::Blankslate`.
9
+ class BlankslateApiMigration < Linter
10
+ include ERBLint::LinterRegistry
11
+ include Helpers::RubocopHelpers
12
+
13
+ def run(processed_source)
14
+ processed_source.ast.descendants(:erb).each do |erb_node|
15
+ _, _, code_node = *erb_node
16
+ code = code_node.children.first.strip
17
+
18
+ next unless code.include?("Primer::BlankslateComponent")
19
+ # Don't fix custom blankslates
20
+ next if code.end_with?("do", "|")
21
+
22
+ line = erb_node.loc.source_line
23
+ indent = line.split("<%=").first.size
24
+
25
+ ast = erb_ast(code)
26
+ kwargs = ast.arguments.first.arguments.last
27
+
28
+ replacement = build_replacement_blankslate(kwargs, indent)
29
+
30
+ add_offense(processed_source.to_source_range(erb_node.loc), "`Primer::BlankslateComponent` is deprecated. `Primer::Beta::Blankslate` should be used instead", replacement)
31
+ end
32
+ end
33
+
34
+ def autocorrect(_, offense)
35
+ return unless offense.context
36
+
37
+ lambda do |corrector|
38
+ corrector.replace(offense.source_range, offense.context)
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def build_blankslate_arguments(kwargs)
45
+ new_blankslate = {
46
+ arguments: {},
47
+ slots: {
48
+ visual_icon: {},
49
+ visual_image: {},
50
+ heading: {
51
+ tag: ":h2"
52
+ },
53
+ description: {},
54
+ primary_action: {},
55
+ secondary_action: {}
56
+ }
57
+ }
58
+
59
+ kwargs&.pairs&.each do |pair|
60
+ source_value = pair.value.source
61
+
62
+ case pair.key.value.to_sym
63
+ when :title
64
+ new_blankslate[:slots][:heading][:content] = extract_value(pair.value)
65
+ when :title_tag
66
+ new_blankslate[:slots][:heading][:tag] = source_value
67
+ when :icon
68
+ new_blankslate[:slots][:visual_icon][:icon] = source_value
69
+ when :icon_size
70
+ new_blankslate[:slots][:visual_icon][:size] = source_value
71
+ when :image_src
72
+ new_blankslate[:slots][:visual_image][:src] = source_value
73
+ when :image_alt
74
+ new_blankslate[:slots][:visual_image][:alt] = source_value
75
+ when :description
76
+ new_blankslate[:slots][:description][:content] = extract_value(pair.value)
77
+ when :button_text
78
+ new_blankslate[:slots][:primary_action][:content] = extract_value(pair.value)
79
+ when :button_url
80
+ new_blankslate[:slots][:primary_action][:href] = source_value
81
+ when :button_classes
82
+ new_blankslate[:slots][:primary_action][:classes] = source_value
83
+ when :link_text
84
+ new_blankslate[:slots][:secondary_action][:content] = extract_value(pair.value)
85
+ when :link_url
86
+ new_blankslate[:slots][:secondary_action][:href] = source_value
87
+ when :large
88
+ next # Large does not exist anymore
89
+ else
90
+ new_blankslate[:arguments][pair.key.source] = source_value
91
+ end
92
+ end
93
+
94
+ new_blankslate
95
+ end
96
+
97
+ def build_replacement_blankslate(kwargs, indent)
98
+ data = build_blankslate_arguments(kwargs)
99
+ component_args = args_to_s(data[:arguments])
100
+
101
+ # If Blankslate has no heading, we don't update it.
102
+ return if data[:slots][:heading][:content].nil?
103
+ # If Blankslate sets both image and icon. don't update it.
104
+ return if data[:slots][:visual_icon].present? && data[:slots][:visual_image].present?
105
+
106
+ slots = data[:slots].map do |slot, slot_data|
107
+ next if slot_data.empty?
108
+
109
+ slot_args = args_to_s(slot_data.except(:content))
110
+ content = slot_data[:content]
111
+
112
+ if content
113
+ <<~HTML.indent(2)
114
+ <% c.#{slot}#{slot_args} do %>
115
+ #{content}
116
+ <% end %>
117
+ HTML
118
+ else
119
+ <<~HTML.indent(2)
120
+ <% c.#{slot}#{slot_args} %>
121
+ HTML
122
+ end
123
+ end.compact.join("\n").chomp
124
+
125
+ # Body needs to match the file indentation.
126
+ body = <<~HTML.indent(indent).chomp
127
+ #{slots}
128
+ <% end %>
129
+ HTML
130
+
131
+ # The render call will always be aligned.
132
+ "<%= render Primer::Beta::Blankslate.new#{component_args} do |c| %>\n#{body}"
133
+ end
134
+
135
+ def args_to_s(args)
136
+ string_args = args.except(:__polymorphic_type).map { |k, v| "#{k}: #{v}" }.join(", ")
137
+
138
+ string_args = ":#{args[:__polymorphic_type]}, #{string_args}" if args[:__polymorphic_type]
139
+
140
+ return string_args if string_args.blank?
141
+
142
+ "(#{string_args})"
143
+ end
144
+
145
+ def extract_value(value)
146
+ return value.value if value.type == :str
147
+
148
+ "<%= #{value.source} %>"
149
+ end
150
+ end
151
+ end
152
+ end
@@ -6,7 +6,7 @@ module ERBLint
6
6
  module Linters
7
7
  # Counts the number of times a HTML Blankslate is used instead of the component.
8
8
  class BlankslateComponentMigrationCounter < BaseLinter
9
- MESSAGE = "We are migrating Blankslate to use [Primer::BlankslateComponent](https://primer.style/view-components/components/blankslate), please try to use that instead of raw HTML."
9
+ MESSAGE = "We are migrating Blankslate to use [Primer::Beta::Blankslate](https://primer.style/view-components/components/beta/blankslate), please try to use that instead of raw HTML."
10
10
  CLASSES = %w[blankslate].freeze
11
11
  TAGS = %w[div].freeze
12
12
  end
@@ -3,12 +3,14 @@
3
3
  require_relative "base_linter"
4
4
  require_relative "autocorrectable"
5
5
  require_relative "argument_mappers/close_button"
6
+ require_relative "helpers/rubocop_helpers"
6
7
 
7
8
  module ERBLint
8
9
  module Linters
9
10
  # Counts the number of times a HTML clipboard-copy is used instead of the component.
10
11
  class CloseButtonComponentMigrationCounter < BaseLinter
11
12
  include Autocorrectable
13
+ include Helpers::RubocopHelpers
12
14
 
13
15
  TAGS = %w[button].freeze
14
16
  CLASSES = %w[close-button].freeze
@@ -109,10 +111,6 @@ module ERBLint
109
111
  (kwargs.keys.map { |key| key.value.to_s } - ALLOWED_OCTICON_ARGS).present?
110
112
  end
111
113
 
112
- def erb_ast(code)
113
- RuboCop::AST::ProcessedSource.new(code, RUBY_VERSION.to_f).ast
114
- end
115
-
116
114
  def icon(args)
117
115
  return args.first.value.to_sym if args.first.type == :sym || args.first.type == :str
118
116
 
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ERBLint
4
+ module Linters
5
+ module Helpers
6
+ # Provides helpers related to RuboCop.
7
+ module RubocopHelpers
8
+ def erb_ast(code)
9
+ RuboCop::AST::ProcessedSource.new(code, RUBY_VERSION.to_f).ast
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ERBLint
4
+ module Linters
5
+ # Helpers used by linters to organize HTML tags into abstract syntax trees.
6
+ module TagTreeHelpers
7
+ # from https://github.com/Shopify/erb-lint/blob/6179ee2d9d681a6ec4dd02351a1e30eefa748d3d/lib/erb_lint/linters/self_closing_tag.rb
8
+ SELF_CLOSING_TAGS = %w[
9
+ area base br col command embed hr input keygen
10
+ link menuitem meta param source track wbr img
11
+ ].freeze
12
+
13
+ # This assumes that the AST provided represents valid HTML, where each tag has a corresponding closing tag.
14
+ # From the tags, we build a structured tree which represents the tag hierarchy.
15
+ # With this, we are able to know where the tags start and end.
16
+ def build_tag_tree(processed_source)
17
+ nodes = processed_source.ast.children
18
+ tag_tree = {}
19
+ tags = []
20
+ current_opened_tag = nil
21
+
22
+ nodes.each do |node|
23
+ if node.type == :tag
24
+ # get the tag from previously calculated list so the references are the same
25
+ tag = BetterHtml::Tree::Tag.from_node(node)
26
+ tags << tag
27
+
28
+ if tag.closing?
29
+ if current_opened_tag && tag.name == current_opened_tag.name
30
+ tag_tree[current_opened_tag][:closing] = tag
31
+ current_opened_tag = tag_tree[current_opened_tag][:parent]
32
+ end
33
+
34
+ next
35
+ end
36
+
37
+ self_closing = self_closing?(tag)
38
+
39
+ tag_tree[tag] = {
40
+ tag: tag,
41
+ closing: self_closing ? tag : nil,
42
+ parent: current_opened_tag,
43
+ children: []
44
+ }
45
+
46
+ tag_tree[current_opened_tag][:children] << tag_tree[tag] if current_opened_tag
47
+ current_opened_tag = tag unless self_closing
48
+ elsif current_opened_tag
49
+ tag_tree[current_opened_tag][:children] << node
50
+ end
51
+ end
52
+
53
+ [tags, tag_tree]
54
+ end
55
+
56
+ def self_closing?(tag)
57
+ tag.self_closing? || SELF_CLOSING_TAGS.include?(tag.name)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,158 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base_linter"
4
+ require_relative "tag_tree_helpers"
5
+
6
+ module ERBLint
7
+ module Linters
8
+ # Counts the number of times a two column layout using col-* CSS classes is used instead of the layout component.
9
+ class TwoColumnLayoutMigrationCounter < BaseLinter
10
+ include LinterRegistry
11
+ include TagTreeHelpers
12
+
13
+ WIDTH_RANGE = (8..10).freeze
14
+ SIDEBAR_WIDTH_RANGE = (2..4).freeze
15
+
16
+ CONTAINER_CLASSES = %w[container-xl container-lg container-md container-sm].freeze
17
+ MESSAGE = "We are migrating two-column layouts to use "\
18
+ "[Primer::Alpha::Layout](https://primer.style/view-components/components/layout), "\
19
+ "please use that instead of raw HTML."
20
+
21
+ # :nodoc:
22
+ class Breakpoints
23
+ LABELS = %i[all sm md lg xl].freeze
24
+
25
+ def initialize
26
+ @map = {}
27
+ end
28
+
29
+ def set(breakpoint, value)
30
+ @map[breakpoint] = value
31
+ end
32
+
33
+ def min
34
+ LABELS.find { |label| @map[label] } || :all
35
+ end
36
+
37
+ def min_value
38
+ @map[min]
39
+ end
40
+ end
41
+
42
+ # :nodoc:
43
+ class Column
44
+ attr_reader :widths, :tag_tree
45
+
46
+ def initialize(widths, tag_tree)
47
+ @widths = widths
48
+ @tag_tree = tag_tree
49
+ end
50
+ end
51
+
52
+ # :nodoc:
53
+ class Container
54
+ attr_reader :columns
55
+
56
+ def initialize(columns)
57
+ @columns = columns
58
+ end
59
+
60
+ def sidebar
61
+ sorted_columns.first
62
+ end
63
+
64
+ def main
65
+ sorted_columns.last
66
+ end
67
+
68
+ private
69
+
70
+ def sorted_columns
71
+ @sorted_columns ||= columns.sort_by do |col|
72
+ col.widths.min_value || 0
73
+ end
74
+ end
75
+ end
76
+
77
+ def run(processed_source)
78
+ @total_offenses = 0
79
+ @offenses_not_corrected = 0
80
+
81
+ tags, tag_tree = build_tag_tree(processed_source)
82
+
83
+ tags.each do |tag|
84
+ next if tag.closing?
85
+ next unless tag.name == "div"
86
+
87
+ classes = classes_from(tag)
88
+ next if (CONTAINER_CLASSES & classes).empty?
89
+
90
+ next unless metadata_from(tag_tree[tag])
91
+
92
+ @total_offenses += 1
93
+ @offenses_not_corrected += 1
94
+
95
+ generate_offense(self.class, processed_source, tag, MESSAGE)
96
+ end
97
+
98
+ counter_correct?(processed_source)
99
+ end
100
+
101
+ private
102
+
103
+ def metadata_from(tag_tree)
104
+ tags = tag_tree[:children].select { |c| c.is_a?(Hash) }
105
+
106
+ if d_flex?(tags)
107
+ container_from(tags.first)
108
+ else
109
+ container_from(tag_tree)
110
+ end
111
+ end
112
+
113
+ def d_flex?(tags)
114
+ tags.size == 1 && classes_from(tags.first[:tag]).include?("d-flex")
115
+ end
116
+
117
+ def container_from(columns_tag_tree)
118
+ columns = columns_from(columns_tag_tree)
119
+ return unless columns.size == 2
120
+
121
+ container = Container.new(columns)
122
+
123
+ main_min = container.main.widths.min_value
124
+ sidebar_min = container.sidebar.widths.min_value
125
+ return unless sidebar_min && main_min
126
+ return unless WIDTH_RANGE.include?(main_min)
127
+ return unless SIDEBAR_WIDTH_RANGE.include?(sidebar_min)
128
+
129
+ container
130
+ end
131
+
132
+ def columns_from(tag_tree)
133
+ tag_tree[:children].each_with_object([]) do |tag_data, tags_memo|
134
+ next unless tag_data.is_a?(Hash)
135
+ next unless tag_data[:tag].name == "div"
136
+
137
+ classes = classes_from(tag_data[:tag])
138
+ widths = Breakpoints.new
139
+
140
+ classes.each do |cls|
141
+ match = cls.match(/\Acol(?:-(xl|lg|md|sm))?-(\d{1,2})(?:-max)?\z/)
142
+ next unless match
143
+
144
+ breakpoint, width = match.captures
145
+ breakpoint ||= :all
146
+ widths.set(breakpoint.to_sym, width.to_i)
147
+ end
148
+
149
+ tags_memo << Column.new(widths, tag_data)
150
+ end
151
+ end
152
+
153
+ def classes_from(tag)
154
+ tag.attributes["class"]&.value&.split(" ") || []
155
+ end
156
+ end
157
+ end
158
+ end
@@ -5,7 +5,7 @@ module Primer
5
5
  module VERSION
6
6
  MAJOR = 0
7
7
  MINOR = 0
8
- PATCH = 60
8
+ PATCH = 64
9
9
 
10
10
  STRING = [MAJOR, MINOR, PATCH].join(".")
11
11
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubocop"
4
+
5
+ module RuboCop
6
+ module Cop
7
+ module Primer
8
+ # This cop ensures that the deprecated `Primer::LayoutComponent` isn't used.
9
+ #
10
+ # bad
11
+ # Primer::LayoutComponent.new(foo: :deprecated)
12
+ #
13
+ # good
14
+ # Primer::Alpha::Layout.new(foo: :deprecated)
15
+ class DeprecatedLayoutComponent < BaseCop
16
+ MSG = "Please try Primer::Alpha::Layout instead."
17
+
18
+ def_node_matcher :legacy_component?, <<~PATTERN
19
+ (send (const (const nil? :Primer) :LayoutComponent) :new ...)
20
+ PATTERN
21
+
22
+ def on_send(node)
23
+ return unless legacy_component?(node)
24
+
25
+ add_offense(node, message: MSG)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -163,9 +163,7 @@ module RuboCop
163
163
 
164
164
  color = case args[:color]
165
165
  when :text_white
166
- :text_white
167
- when :text_link
168
- :icon_info
166
+ :on_emphasis
169
167
  when Symbol
170
168
  args[:color].to_s.gsub("text_", "icon_").to_sym
171
169
  end