primer_view_components 0.0.51 → 0.0.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +159 -0
  3. data/app/components/primer/alpha/tab_nav.html.erb +11 -0
  4. data/app/components/primer/alpha/tab_nav.rb +130 -0
  5. data/app/components/primer/{tab_nav_component.html.erb → alpha/tab_panels.html.erb} +3 -8
  6. data/app/components/primer/alpha/tab_panels.rb +82 -0
  7. data/app/components/primer/alpha/underline_nav.html.erb +15 -0
  8. data/app/components/primer/alpha/underline_nav.rb +137 -0
  9. data/app/components/primer/{underline_nav_component.html.erb → alpha/underline_panels.html.erb} +3 -8
  10. data/app/components/primer/alpha/underline_panels.rb +86 -0
  11. data/app/components/primer/base_component.rb +1 -1
  12. data/app/components/primer/beta/avatar_stack.rb +9 -9
  13. data/app/components/primer/{breadcrumb_component.html.erb → beta/breadcrumbs.html.erb} +2 -1
  14. data/app/components/primer/beta/breadcrumbs.rb +61 -0
  15. data/app/components/primer/beta/truncate.html.erb +5 -0
  16. data/app/components/primer/beta/truncate.rb +110 -0
  17. data/app/components/primer/border_box_component.rb +27 -1
  18. data/app/components/primer/clipboard_copy.rb +1 -1
  19. data/app/components/primer/dropdown.rb +7 -7
  20. data/app/components/primer/icon_button.rb +1 -1
  21. data/app/components/primer/navigation/tab_component.rb +8 -6
  22. data/app/components/primer/octicon_component.rb +6 -1
  23. data/app/components/primer/progress_bar_component.rb +0 -3
  24. data/app/components/primer/tab_container_component.rb +1 -1
  25. data/app/lib/primer/class_name_helper.rb +14 -13
  26. data/app/lib/primer/fetch_or_fallback_helper.rb +2 -0
  27. data/app/lib/primer/octicon/cache.rb +10 -2
  28. data/app/lib/primer/tab_nav_helper.rb +35 -0
  29. data/app/lib/primer/tabbed_component_helper.rb +5 -5
  30. data/app/lib/primer/underline_nav_helper.rb +44 -0
  31. data/app/lib/primer/view_helper.rb +1 -0
  32. data/lib/primer/classify/cache.rb +0 -6
  33. data/lib/primer/classify/flex.rb +1 -1
  34. data/lib/primer/classify/functional_colors.rb +1 -1
  35. data/lib/primer/classify/utilities.rb +17 -2
  36. data/lib/primer/classify/utilities.yml +35 -0
  37. data/lib/primer/classify/validation.rb +18 -0
  38. data/lib/primer/classify.rb +4 -13
  39. data/lib/primer/view_components/constants.rb +1 -1
  40. data/lib/primer/view_components/linters/argument_mappers/base.rb +34 -8
  41. data/lib/primer/view_components/linters/argument_mappers/button.rb +5 -6
  42. data/lib/primer/view_components/linters/argument_mappers/clipboard_copy.rb +4 -3
  43. data/lib/primer/view_components/linters/argument_mappers/close_button.rb +43 -0
  44. data/lib/primer/view_components/linters/argument_mappers/flash.rb +32 -0
  45. data/lib/primer/view_components/linters/argument_mappers/helpers/erb_block.rb +48 -5
  46. data/lib/primer/view_components/linters/argument_mappers/label.rb +3 -4
  47. data/lib/primer/view_components/linters/argument_mappers/system_arguments.rb +5 -7
  48. data/lib/primer/view_components/linters/autocorrectable.rb +6 -4
  49. data/lib/primer/view_components/linters/{helpers.rb → base_linter.rb} +69 -29
  50. data/lib/primer/view_components/linters/button_component_migration_counter.rb +4 -3
  51. data/lib/primer/view_components/linters/clipboard_copy_component_migration_counter.rb +3 -4
  52. data/lib/primer/view_components/linters/close_button_component_migration_counter.rb +110 -3
  53. data/lib/primer/view_components/linters/flash_component_migration_counter.rb +18 -3
  54. data/lib/primer/view_components/linters/label_component_migration_counter.rb +2 -3
  55. data/lib/primer/view_components/version.rb +1 -1
  56. data/lib/rubocop/config/default.yml +5 -0
  57. data/lib/rubocop/cop/primer/base_cop.rb +28 -0
  58. data/lib/rubocop/cop/primer/deprecated_arguments.rb +263 -0
  59. data/lib/rubocop/cop/primer/no_tag_memoize.rb +1 -0
  60. data/lib/rubocop/cop/primer/primer_octicon.rb +178 -0
  61. data/lib/rubocop/cop/primer/system_argument_instead_of_class.rb +4 -32
  62. data/lib/rubocop/cop/primer.rb +1 -2
  63. data/lib/tasks/coverage.rake +4 -0
  64. data/lib/tasks/docs.rake +10 -8
  65. data/lib/tasks/utilities.rake +7 -3
  66. data/lib/yard/docs_helper.rb +6 -3
  67. data/static/arguments.yml +82 -64
  68. data/static/classes.yml +10 -0
  69. data/static/constants.json +44 -30
  70. data/static/statuses.json +10 -6
  71. metadata +57 -18
  72. data/app/components/primer/auto_complete/auto_component.d.ts +0 -1
  73. data/app/components/primer/auto_complete/auto_component.js +0 -1
  74. data/app/components/primer/breadcrumb_component.rb +0 -57
  75. data/app/components/primer/tab_nav_component.rb +0 -151
  76. data/app/components/primer/underline_nav_component.rb +0 -187
  77. data/lib/primer/classify/functional_text_colors.rb +0 -64
@@ -1,14 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "helpers"
3
+ require_relative "base_linter"
4
4
  require_relative "autocorrectable"
5
5
  require_relative "argument_mappers/label"
6
6
 
7
7
  module ERBLint
8
8
  module Linters
9
9
  # Counts the number of times a HTML label is used instead of the component.
10
- class LabelComponentMigrationCounter < Linter
11
- include Helpers
10
+ class LabelComponentMigrationCounter < BaseLinter
12
11
  include Autocorrectable
13
12
 
14
13
  TAGS = Primer::ViewComponents::Constants.get(
@@ -5,7 +5,7 @@ module Primer
5
5
  module VERSION
6
6
  MAJOR = 0
7
7
  MINOR = 0
8
- PATCH = 51
8
+ PATCH = 55
9
9
 
10
10
  STRING = [MAJOR, MINOR, PATCH].join(".")
11
11
  end
@@ -10,3 +10,8 @@ Primer/SystemArgumentInsteadOfClass:
10
10
  Primer/NoTagMemoize:
11
11
  Enabled: false
12
12
 
13
+ Primer/PrimerOcticon:
14
+ Enabled: true
15
+
16
+ Primer/DeprecatedArguments:
17
+ Enabled: true
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubocop"
4
+ require "primer/view_components/statuses"
5
+ require_relative "../../../../app/lib/primer/view_helper"
6
+
7
+ module RuboCop
8
+ module Cop
9
+ module Primer
10
+ # :nodoc:
11
+ class BaseCop < RuboCop::Cop::Cop
12
+ # We only verify SystemArguments if it's a `.new` call on a component or
13
+ # a ViewHeleper call.
14
+ def valid_node?(node)
15
+ return if node.nil?
16
+
17
+ view_helpers.include?(node.method_name) || (node.method_name == :new && !node.receiver.nil? && ::Primer::ViewComponents::STATUSES.key?(node.receiver.const_name))
18
+ end
19
+
20
+ private
21
+
22
+ def view_helpers
23
+ ::Primer::ViewHelper::HELPERS.keys.map { |key| "primer_#{key}".to_sym }
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,263 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubocop"
4
+
5
+ # :nocov:
6
+ module RuboCop
7
+ module Cop
8
+ module Primer
9
+ # This cop ensures that components don't use deprecated arguments
10
+ #
11
+ # bad
12
+ # Component.new(foo: :deprecated)
13
+ #
14
+ # good
15
+ # Component.new(foo: :bar)
16
+ class DeprecatedArguments < BaseCop
17
+ INVALID_MESSAGE = <<~STR
18
+ Avoid using deprecated arguments: https://primer.style/view-components/deprecated.
19
+ STR
20
+
21
+ # This is a hash of deprecated arguments and their replacements.
22
+ #
23
+ # * The top level key is the argument.
24
+ # * The second level key is the value.
25
+ # * The seceond level value is a string of the full replacement. e.g. "new_argument: :new_value"
26
+ # If the value is nil, then there is no replacement.
27
+ #
28
+ # e.g.
29
+ # DEPRECATED = {
30
+ # argument: {
31
+ # value: "new_argument: :new_value"
32
+ # }
33
+ # }
34
+ #
35
+ DEPRECATED = {
36
+ bg: {
37
+ white: "bg: :primary",
38
+ gray_light: "bg: :secondary",
39
+ gray: "bg: :tertiary",
40
+ gray_dark: "bg: :canvas_inverse",
41
+ blue_light: "bg: :info",
42
+ blue: "bg: :info_inverse",
43
+ green_light: "bg: :success",
44
+ green: "bg: :success_inverse",
45
+ yellow_light: "bg: :warning",
46
+ yellow: "bg: :warning_inverse",
47
+ red_light: "bg: :danger",
48
+ red: "bg: :danger_inverse",
49
+ gray_0: nil,
50
+ gray_1: nil,
51
+ gray_2: nil,
52
+ gray_3: nil,
53
+ gray_4: nil,
54
+ gray_5: nil,
55
+ gray_6: nil,
56
+ gray_7: nil,
57
+ gray_8: nil,
58
+ gray_9: nil,
59
+ blue_0: nil,
60
+ blue_1: nil,
61
+ blue_2: nil,
62
+ blue_3: nil,
63
+ blue_4: nil,
64
+ blue_5: nil,
65
+ blue_6: nil,
66
+ blue_7: nil,
67
+ blue_8: nil,
68
+ blue_9: nil,
69
+ green_0: nil,
70
+ green_1: nil,
71
+ green_2: nil,
72
+ green_3: nil,
73
+ green_4: nil,
74
+ green_5: nil,
75
+ green_6: nil,
76
+ green_7: nil,
77
+ green_8: nil,
78
+ green_9: nil,
79
+ yellow_0: nil,
80
+ yellow_1: nil,
81
+ yellow_2: nil,
82
+ yellow_3: nil,
83
+ yellow_4: nil,
84
+ yellow_5: nil,
85
+ yellow_6: nil,
86
+ yellow_7: nil,
87
+ yellow_8: nil,
88
+ yellow_9: nil,
89
+ red_0: nil,
90
+ red_1: nil,
91
+ red_2: nil,
92
+ red_3: nil,
93
+ red_4: nil,
94
+ red_5: nil,
95
+ red_6: nil,
96
+ red_7: nil,
97
+ red_8: nil,
98
+ red_9: nil,
99
+ purple_0: nil,
100
+ purple_1: nil,
101
+ purple_2: nil,
102
+ purple_3: nil,
103
+ purple_4: nil,
104
+ purple_5: nil,
105
+ purple_6: nil,
106
+ purple_7: nil,
107
+ purple_8: nil,
108
+ purple_9: nil,
109
+ pink_0: nil,
110
+ pink_1: nil,
111
+ pink_2: nil,
112
+ pink_3: nil,
113
+ pink_4: nil,
114
+ pink_5: nil,
115
+ pink_6: nil,
116
+ pink_7: nil,
117
+ pink_8: nil,
118
+ pink_9: nil,
119
+ orange_0: nil,
120
+ orange_1: nil,
121
+ orange_2: nil,
122
+ orange_3: nil,
123
+ orange_4: nil,
124
+ orange_5: nil,
125
+ orange_6: nil,
126
+ orange_7: nil,
127
+ orange_8: nil,
128
+ orange_9: nil
129
+ },
130
+ border_color: {
131
+ gray: "border_color: :primary",
132
+ gray_light: "border_color: :secondary",
133
+ gray_dark: "border_color: :tertiary",
134
+ blue: "border_color: :info",
135
+ green: "border_color: :success",
136
+ yellow: "border_color: :warning",
137
+ red: "border_color: :danger",
138
+ white: "border_color: :inverse"
139
+ },
140
+ color: {
141
+ blue: "color: :text_link",
142
+ gray_dark: "color: :text_primary",
143
+ gray: "color: :text_secondary",
144
+ gray_light: "color: :text_tertiary",
145
+ green: "color: :text_success",
146
+ yellow: "color: :text_warning",
147
+ red: "color: :text_danger",
148
+ gray_0: nil,
149
+ gray_1: nil,
150
+ gray_2: nil,
151
+ gray_3: nil,
152
+ gray_4: nil,
153
+ gray_5: nil,
154
+ gray_6: nil,
155
+ gray_7: nil,
156
+ gray_8: nil,
157
+ gray_9: nil,
158
+ blue_0: nil,
159
+ blue_1: nil,
160
+ blue_2: nil,
161
+ blue_3: nil,
162
+ blue_4: nil,
163
+ blue_5: nil,
164
+ blue_6: nil,
165
+ blue_7: nil,
166
+ blue_8: nil,
167
+ blue_9: nil,
168
+ green_0: nil,
169
+ green_1: nil,
170
+ green_2: nil,
171
+ green_3: nil,
172
+ green_4: nil,
173
+ green_5: nil,
174
+ green_6: nil,
175
+ green_7: nil,
176
+ green_8: nil,
177
+ green_9: nil,
178
+ yellow_0: nil,
179
+ yellow_1: nil,
180
+ yellow_2: nil,
181
+ yellow_3: nil,
182
+ yellow_4: nil,
183
+ yellow_5: nil,
184
+ yellow_6: nil,
185
+ yellow_7: nil,
186
+ yellow_8: nil,
187
+ yellow_9: nil,
188
+ red_0: nil,
189
+ red_1: nil,
190
+ red_2: nil,
191
+ red_3: nil,
192
+ red_4: nil,
193
+ red_5: nil,
194
+ red_6: nil,
195
+ red_7: nil,
196
+ red_8: nil,
197
+ red_9: nil,
198
+ purple_0: nil,
199
+ purple_1: nil,
200
+ purple_2: nil,
201
+ purple_3: nil,
202
+ purple_4: nil,
203
+ purple_5: nil,
204
+ purple_6: nil,
205
+ purple_7: nil,
206
+ purple_8: nil,
207
+ purple_9: nil,
208
+ pink_0: nil,
209
+ pink_1: nil,
210
+ pink_2: nil,
211
+ pink_3: nil,
212
+ pink_4: nil,
213
+ pink_5: nil,
214
+ pink_6: nil,
215
+ pink_7: nil,
216
+ pink_8: nil,
217
+ pink_9: nil,
218
+ orange_0: nil,
219
+ orange_1: nil,
220
+ orange_2: nil,
221
+ orange_3: nil,
222
+ orange_4: nil,
223
+ orange_5: nil,
224
+ orange_6: nil,
225
+ orange_7: nil,
226
+ orange_8: nil,
227
+ orange_9: nil
228
+ }
229
+ }.freeze
230
+
231
+ def on_send(node)
232
+ return unless valid_node?(node)
233
+ return unless node.arguments?
234
+
235
+ # we are looking for hash arguments and they are always last
236
+ kwargs = node.arguments.last
237
+
238
+ return unless kwargs.type == :hash
239
+
240
+ kwargs.pairs.each do |pair|
241
+ # Skip if we're not dealing with a symbol
242
+ next if pair.key.type != :sym
243
+ next unless pair.value.type == :sym || pair.value.type == :str
244
+
245
+ key = pair.key.value
246
+ value = pair.value.value.to_sym
247
+
248
+ next unless DEPRECATED.key?(key) && DEPRECATED[key].key?(value)
249
+
250
+ add_offense(pair, message: INVALID_MESSAGE)
251
+ end
252
+ end
253
+
254
+ def autocorrect(node)
255
+ lambda do |corrector|
256
+ replacement = DEPRECATED[node.key.value][node.value.value.to_sym]
257
+ corrector.replace(node, replacement) if replacement.present?
258
+ end
259
+ end
260
+ end
261
+ end
262
+ end
263
+ end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "rubocop"
4
4
 
5
+ # :nocov:
5
6
  module RuboCop
6
7
  module Cop
7
8
  module Primer
@@ -0,0 +1,178 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubocop"
4
+ require "primer/classify/utilities"
5
+ require "primer/classify/validation"
6
+
7
+ # :nocov:
8
+ module RuboCop
9
+ module Cop
10
+ module Primer
11
+ # This cop ensures that components use System Arguments instead of CSS classes.
12
+ #
13
+ # bad
14
+ # octicon(:icon)
15
+ # octicon("icon")
16
+ # octicon("icon-with-daashes")
17
+ # octicon(@ivar)
18
+ # octicon(condition > "icon" : "other-icon")
19
+ #
20
+ # good
21
+ # primer_octicon(:icon)
22
+ # primer_octicon(:"icon-with-daashes")
23
+ # primer_octicon(@ivar)
24
+ # primer_octicon(condition > "icon" : "other-icon")
25
+ class PrimerOcticon < RuboCop::Cop::Cop
26
+ INVALID_MESSAGE = <<~STR
27
+ Replace the octicon helper with primer_octicon. See https://primer.style/view-components/components/octicon for details.
28
+ STR
29
+
30
+ SIZE_ATTRIBUTES = %w[height width size].freeze
31
+ STRING_ATTRIBUTES = %w[aria- data-].freeze
32
+ VALID_ATTRIBUTES = [*SIZE_ATTRIBUTES, *STRING_ATTRIBUTES, "class"].freeze
33
+
34
+ STRING_ATTRIBUTE_REGEX = Regexp.union(STRING_ATTRIBUTES).freeze
35
+ ATTRIBUTE_REGEX = Regexp.union(VALID_ATTRIBUTES).freeze
36
+ INVALID_ATTRIBUTE = -1
37
+
38
+ def on_send(node)
39
+ return unless node.method_name == :octicon
40
+ return unless node.arguments?
41
+
42
+ kwargs = kwargs(node)
43
+
44
+ return unless kwargs.type == :hash
45
+
46
+ attributes = kwargs.keys.map(&:value)
47
+
48
+ # Don't convert unknown attributes
49
+ return unless attributes.all? { |attribute| attribute.match?(ATTRIBUTE_REGEX) }
50
+ # Can't convert size
51
+ return if octicon_size_attributes(kwargs) == INVALID_ATTRIBUTE
52
+
53
+ # find class pair
54
+ classes = classes(kwargs)
55
+
56
+ return if classes == INVALID_ATTRIBUTE
57
+
58
+ # check if classes are convertible
59
+ if classes.present?
60
+ system_arguments = ::Primer::Classify::Utilities.classes_to_hash(classes)
61
+ invalid_classes = (system_arguments[:classes]&.split(" ") || []).select { |class_name| ::Primer::Classify::Validation.invalid?(class_name) }
62
+
63
+ # Uses system argument that can't be converted
64
+ return if invalid_classes.present?
65
+ end
66
+
67
+ add_offense(node, message: INVALID_MESSAGE)
68
+ end
69
+
70
+ def autocorrect(node)
71
+ lambda do |corrector|
72
+ kwargs = kwargs(node)
73
+
74
+ # Converting arguments for the component
75
+ classes = classes(kwargs)
76
+ size_attributes = transform_sizes(kwargs)
77
+ args = arguments_as_string(node, size_attributes, classes)
78
+
79
+ corrector.replace(node.loc.expression, "primer_octicon(#{args})")
80
+ end
81
+ end
82
+
83
+ private
84
+
85
+ def transform_sizes(kwargs)
86
+ attributes = octicon_size_attributes(kwargs)
87
+
88
+ attributes.transform_values do |size|
89
+ if size.between?(10, 16)
90
+ ""
91
+ elsif size.between?(22, 26)
92
+ ":medium"
93
+ else
94
+ size
95
+ end
96
+ end
97
+ end
98
+
99
+ def octicon_size_attributes(kwargs)
100
+ kwargs.pairs.each_with_object({}) do |pair, h|
101
+ next unless SIZE_ATTRIBUTES.include?(pair.key.value.to_s)
102
+
103
+ # We only support string or int values.
104
+ case pair.value.type
105
+ when :int
106
+ h[pair.key.value] = pair.value.source.to_i
107
+ when :str
108
+ h[pair.key.value] = pair.value.value.to_i
109
+ else
110
+ return INVALID_ATTRIBUTE
111
+ end
112
+ end
113
+ end
114
+
115
+ def classes(kwargs)
116
+ # find class pair
117
+ class_arg = kwargs.pairs.find { |kwarg| kwarg.key.value == :class }
118
+
119
+ return if class_arg.blank?
120
+ return INVALID_ATTRIBUTE unless class_arg.value.type == :str
121
+
122
+ class_arg.value.value
123
+ end
124
+
125
+ def arguments_as_string(node, size_attributes, classes)
126
+ args = icon(node.arguments.first)
127
+ size_args = size_attributes_to_string(size_attributes)
128
+ string_args = string_args_to_string(node)
129
+
130
+ args = "#{args}, #{size_attributes_to_string(size_attributes)}" if size_args.present?
131
+ args = "#{args}, #{::Primer::Classify::Utilities.classes_to_args(classes)}" if classes.present?
132
+ args = "#{args}, #{string_args}" if string_args.present?
133
+
134
+ args
135
+ end
136
+
137
+ def size_attributes_to_string(size_attributes)
138
+ # No arguments if they map to the default size
139
+ return if size_attributes.blank? || size_attributes.values.all?(&:blank?)
140
+ # Return mapped argument to `size`
141
+ return "size: :medium" if size_attributes.values.any?(":medium")
142
+
143
+ size_attributes.map do |key, value|
144
+ "#{key}: #{value}"
145
+ end.join(", ")
146
+ end
147
+
148
+ def string_args_to_string(node)
149
+ kwargs = kwargs(node)
150
+
151
+ args = kwargs.pairs.each_with_object([]) do |pair, acc|
152
+ next unless pair.key.value.to_s.match?(STRING_ATTRIBUTE_REGEX)
153
+
154
+ key = pair.key.value.to_s == "data-test-selector" ? "test_selector" : "\"#{pair.key.value}\""
155
+ acc << "#{key}: #{pair.value.source}"
156
+ end
157
+
158
+ args.join(",")
159
+ end
160
+
161
+ def kwargs(node)
162
+ return node.arguments.last if node.arguments.size > 1
163
+
164
+ OpenStruct.new(keys: [], pairs: [], type: :hash)
165
+ end
166
+
167
+ def icon(node)
168
+ return node.source unless node.type == :str
169
+ return ":#{node.value}" unless node.value.include?("-")
170
+
171
+ # If the icon contains `-` we need to cast the string as a symbole
172
+ # E.g: `arrow-down` becomes `:"arrow-down"`
173
+ ":#{node.source}"
174
+ end
175
+ end
176
+ end
177
+ end
178
+ end