primer_view_components 0.0.47 → 0.0.48

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1b0ba62c9f5f11df09d24b40ca5e61e7d618046aba651ad733c8db06c482fe26
4
- data.tar.gz: 34c0b8066b85d5392dd241baeb3b654ba47d7de1f360b793ac893750989d99dd
3
+ metadata.gz: 2c751bc60362c19e97ba5fbe22227e19186efa799862932a6f7b8541ad8e1eaa
4
+ data.tar.gz: 4efd584159e4883f8bcc72954fff356c753b0b8980056ee0c58b7a3bd650cb90
5
5
  SHA512:
6
- metadata.gz: 47e1bca34582e4406fcc268ac786a322cc3f99a62789aeece262b91e1ca26a15c145835ad60afbcd85a13b3a37da7a54541aedf8e2af5b60c43d7d6cf6767072
7
- data.tar.gz: 2edfb035e82896ea22bec576a98b34eb2e3c18cccf2d3ba18744f7b77135f6a1310b466179025c216d396708fdf5fbe802a2dc436c57d1510632eb9567776df1
6
+ metadata.gz: c6169f90241d046f9cee4faf1fb971cac34360c8ebb116e2c2e39fdd0aeff5e8cca17e899bdd8a97f94ebefa4c3705d6929b0978a96f0264dcab3fa96342faaf
7
+ data.tar.gz: 8576857a521647f43ccb3fe413b0e24b5d65a8c06e9036dd3035b37d8fb5989aa43a7ac2d33863f5faa022c099c6a8386d30de8b764e19cf93b9dcb207fd4eef
data/CHANGELOG.md CHANGED
@@ -30,6 +30,24 @@ The category for changes related to documentation, testing and tooling. Also, fo
30
30
 
31
31
  ## main
32
32
 
33
+ ## 0.0.48
34
+
35
+ ### Breaking changes
36
+
37
+ * Ensure panels in `Navigation::Tab` have a label.
38
+
39
+ *Kate Higa*
40
+
41
+ ### Misc
42
+
43
+ * Expose custom cops and default config for erblint.
44
+
45
+ *Manuel Puyol*
46
+
47
+ * Fix double constant assign.
48
+
49
+ *Manuel Puyol*
50
+
33
51
  ## 0.0.47
34
52
 
35
53
  ### Breaking changes
@@ -12,7 +12,7 @@ module Primer
12
12
  TAG_OPTIONS = [DEFAULT_TAG, :span].freeze
13
13
 
14
14
  DEFAULT_BODY_TAG = :div
15
- BODY_TAG_OPTIONS = TAG_OPTIONS = [DEFAULT_TAG, :span].freeze
15
+ BODY_TAG_OPTIONS = [DEFAULT_BODY_TAG, :span].freeze
16
16
  # Required list of stacked avatars.
17
17
  #
18
18
  # @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::Beta::Avatar) %>.
@@ -29,7 +29,7 @@ module Primer
29
29
  # @param type [Symbol] <%= one_of(Primer::Beta::AutoComplete::Input::TYPE_OPTIONS) %>
30
30
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
31
31
  renders_one :input, lambda { |**system_arguments|
32
- aria_label = system_arguments[:"aria-label"] || system_arguments.dig(:aria, :label) || @aria_label
32
+ aria_label = aria("label", system_arguments) || @aria_label
33
33
  if aria_label.present?
34
34
  system_arguments[:"aria-label"] = aria_label
35
35
  system_arguments[:aria]&.delete(:label)
@@ -106,7 +106,7 @@ module Primer
106
106
  def initialize(src:, list_id:, input_id:, **system_arguments)
107
107
  @list_id = list_id
108
108
  @input_id = input_id
109
- @aria_label = system_arguments[:"aria-label"] || system_arguments.dig(:aria, :label)
109
+ @aria_label = aria("label", system_arguments)
110
110
 
111
111
  system_arguments.delete(:"aria-label") && system_arguments[:aria]&.delete(:label)
112
112
 
@@ -29,8 +29,12 @@ module Primer
29
29
  ActiveSupport::Deprecation.warn(message)
30
30
  end
31
31
 
32
+ def aria(val, system_arguments)
33
+ system_arguments[:"aria-#{val}"] || system_arguments.dig(:aria, val.to_sym)
34
+ end
35
+
32
36
  def validate_aria_label
33
- aria_label = @system_arguments[:"aria-label"] || @system_arguments.dig(:aria, :label)
37
+ aria_label = aria("label", @system_arguments)
34
38
  raise ArgumentError, "`aria-label` is required." if aria_label.nil? && !Rails.env.production?
35
39
  end
36
40
 
@@ -18,10 +18,22 @@ module Primer
18
18
  #
19
19
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
20
20
  renders_one :panel, lambda { |**system_arguments|
21
+ return unless @with_panel
22
+
21
23
  system_arguments[:tag] = :div
22
24
  system_arguments[:role] ||= :tabpanel
25
+ system_arguments[:tabindex] = 0
23
26
  system_arguments[:hidden] = true unless @selected
24
27
 
28
+ label_present = aria("label", system_arguments) || aria("labelledby", system_arguments)
29
+ unless label_present
30
+ if @id.present?
31
+ system_arguments[:"aria-labelledby"] = @id
32
+ elsif !Rails.env.production?
33
+ raise ArgumentError, "Panels must be labelled. Either set a unique `id` on the tab, or set an `aria-label` directly on the panel"
34
+ end
35
+ end
36
+
25
37
  Primer::BaseComponent.new(**system_arguments)
26
38
  }
27
39
 
@@ -93,8 +105,10 @@ module Primer
93
105
  @selected = selected
94
106
  @icon_classes = icon_classes
95
107
  @list = list
108
+ @with_panel = with_panel
96
109
 
97
110
  @system_arguments = system_arguments
111
+ @id = @system_arguments[:id]
98
112
 
99
113
  if with_panel || @system_arguments[:tag] == :button
100
114
  @system_arguments[:tag] = :button
@@ -111,7 +125,7 @@ module Primer
111
125
  return unless @selected
112
126
 
113
127
  if @system_arguments[:tag] == :a
114
- aria_current = @system_arguments[:"aria-current"] || @system_arguments.dig(:aria, :current) || DEFAULT_ARIA_CURRENT_FOR_ANCHOR
128
+ aria_current = aria("current", system_arguments) || DEFAULT_ARIA_CURRENT_FOR_ANCHOR
115
129
  @system_arguments[:"aria-current"] = fetch_or_fallback(ARIA_CURRENT_OPTIONS_FOR_ANCHOR, aria_current, DEFAULT_ARIA_CURRENT_FOR_ANCHOR)
116
130
  else
117
131
  @system_arguments[:"aria-selected"] = true
@@ -63,19 +63,19 @@ module Primer
63
63
  #
64
64
  # @example With panels
65
65
  # <%= render(Primer::TabNavComponent.new(label: "With panels", with_panel: true)) do |c| %>
66
- # <% c.tab(selected: true) do |t| %>
66
+ # <% c.tab(selected: true, id: "tab-1") do |t| %>
67
67
  # <% t.text { "Tab 1" } %>
68
68
  # <% t.panel do %>
69
69
  # Panel 1
70
70
  # <% end %>
71
71
  # <% end %>
72
- # <% c.tab do |t| %>
72
+ # <% c.tab(id: "tab-2") do |t| %>
73
73
  # <% t.text { "Tab 2" } %>
74
74
  # <% t.panel do %>
75
75
  # Panel 2
76
76
  # <% end %>
77
77
  # <% end %>
78
- # <% c.tab do |t| %>
78
+ # <% c.tab(id: "tab-3") do |t| %>
79
79
  # <% t.text { "Tab 3" } %>
80
80
  # <% t.panel do %>
81
81
  # Panel 3
@@ -104,13 +104,13 @@ module Primer
104
104
  #
105
105
  # @example With panels
106
106
  # <%= render(Primer::UnderlineNavComponent.new(label: "With panels", with_panel: true)) do |component| %>
107
- # <% component.tab(selected: true) do |t| %>
107
+ # <% component.tab(selected: true, id: "tab-1") do |t| %>
108
108
  # <% t.text { "Item 1" } %>
109
109
  # <% t.panel do %>
110
110
  # Panel 1
111
111
  # <% end %>
112
112
  # <% end %>
113
- # <% component.tab do |t| %>
113
+ # <% component.tab(id: "tab-2") do |t| %>
114
114
  # <% t.text { "Item 2" } %>
115
115
  # <% t.panel do %>
116
116
  # Panel 2
@@ -5,7 +5,7 @@ module Primer
5
5
  module VERSION
6
6
  MAJOR = 0
7
7
  MINOR = 0
8
- PATCH = 47
8
+ PATCH = 48
9
9
 
10
10
  STRING = [MAJOR, MINOR, PATCH].join(".")
11
11
  end
@@ -0,0 +1,12 @@
1
+ require:
2
+ - rubocop/cop/primer
3
+
4
+ AllCops:
5
+ DisabledByDefault: true
6
+
7
+ Primer/SystemArgumentInsteadOfClass:
8
+ Enabled: true
9
+
10
+ Primer/NoTagMemoize:
11
+ Enabled: false
12
+
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubocop/cop/primer/no_tag_memoize"
4
+ require "rubocop/cop/primer/system_argument_instead_of_class"
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubocop"
4
+
5
+ module RuboCop
6
+ module Cop
7
+ module Primer
8
+ # This cop ensures that tags are not set with ||=
9
+ #
10
+ # bad
11
+ # @system_arguments[:tag] ||= :h1
12
+ #
13
+ # good
14
+ # @system_arguments[:tag] = fetch_or_fallback(TAG_OPTIONS, tag, DEFAULT_TAG)
15
+ #
16
+ # good
17
+ # @system_arguments[:tag] = :h2
18
+ class NoTagMemoize < RuboCop::Cop::Cop
19
+ INVALID_MESSAGE = <<~STR
20
+ Avoid `[:tag] ||=`. Instead, try one of the following:
21
+ - Don't allow consumers to update the tag by having a fixed tag (e.g. `system_arguments[:tag] = :div`)
22
+ - Use the `fetch_or_fallback` helper to only allow a tag from a restricted list.
23
+ STR
24
+
25
+ def_node_search :tag_memoized?, <<~PATTERN
26
+ (or-asgn
27
+ (send
28
+ _
29
+ _
30
+ (sym :tag)
31
+ )
32
+ _
33
+ )
34
+ PATTERN
35
+
36
+ def on_or_asgn(node)
37
+ add_offense(node, message: INVALID_MESSAGE) if tag_memoized?(node)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubocop"
4
+ require "primer/classify/utilities"
5
+ require "primer/view_components/statuses"
6
+
7
+ module RuboCop
8
+ module Cop
9
+ module Primer
10
+ # This cop ensures that components use System Arguments instead of CSS classes.
11
+ #
12
+ # bad
13
+ # Component.new(classes: "mr-1")
14
+ #
15
+ # good
16
+ # Component.new(mr: 1)
17
+ class SystemArgumentInsteadOfClass < RuboCop::Cop::Cop
18
+ INVALID_MESSAGE = <<~STR
19
+ Avoid using CSS classes when you can use System Arguments: https://primer.style/view-components/system-arguments.
20
+ STR
21
+
22
+ def on_send(node)
23
+ return unless node.method_name == :new
24
+ return unless ::Primer::ViewComponents::STATUSES.key?(node.receiver.const_name)
25
+ return unless node.arguments?
26
+
27
+ # we are looking for hash arguments and they are always last
28
+ kwargs = node.arguments.last
29
+
30
+ return unless kwargs.type == :hash
31
+
32
+ # find classes pair
33
+ classes_arg = kwargs.pairs.find { |kwarg| kwarg.key.value == :classes }
34
+
35
+ return if classes_arg.nil?
36
+ return unless classes_arg.value.type == :str
37
+
38
+ # get actual classes
39
+ classes = classes_arg.value.value
40
+
41
+ system_arguments = ::Primer::Classify::Utilities.classes_to_hash(classes)
42
+
43
+ # no classes are fixable
44
+ return if system_arguments[:classes] == classes
45
+
46
+ add_offense(classes_arg, message: INVALID_MESSAGE)
47
+ end
48
+
49
+ def autocorrect(node)
50
+ lambda do |corrector|
51
+ system_arguments = ::Primer::Classify::Utilities.classes_to_hash(node.value.value)
52
+ corrector.replace(node.loc.expression, arguments_as_string(system_arguments))
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def arguments_as_string(system_arguments)
59
+ system_arguments.map do |key, value|
60
+ val = case value
61
+ when Symbol
62
+ ":#{value}"
63
+ when String
64
+ value.to_json
65
+ else
66
+ value
67
+ end
68
+
69
+ "#{key}: #{val}"
70
+ end.join(", ")
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: primer_view_components
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.47
4
+ version: 0.0.48
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub Open Source
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-20 00:00:00.000000000 Z
11
+ date: 2021-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionview
@@ -487,6 +487,10 @@ files:
487
487
  - lib/primer/view_components/linters/helpers.rb
488
488
  - lib/primer/view_components/statuses.rb
489
489
  - lib/primer/view_components/version.rb
490
+ - lib/rubocop/config/default.yml
491
+ - lib/rubocop/cop/primer.rb
492
+ - lib/rubocop/cop/primer/no_tag_memoize.rb
493
+ - lib/rubocop/cop/primer/system_argument_instead_of_class.rb
490
494
  - lib/tasks/coverage.rake
491
495
  - lib/tasks/docs.rake
492
496
  - lib/tasks/statuses.rake