primer_view_components 0.0.61 → 0.0.62

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -2
  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/tab_nav.rb +1 -1
  6. data/app/components/primer/alpha/tab_panels.rb +2 -2
  7. data/app/components/primer/alpha/underline_nav.rb +2 -1
  8. data/app/components/primer/alpha/underline_panels.rb +2 -2
  9. data/app/components/primer/base_component.rb +8 -36
  10. data/app/components/primer/beta/auto_complete/item.rb +1 -1
  11. data/app/components/primer/beta/auto_complete.rb +4 -2
  12. data/app/components/primer/beta/avatar.rb +1 -1
  13. data/app/components/primer/beta/blankslate.html.erb +2 -2
  14. data/app/components/primer/beta/blankslate.rb +6 -3
  15. data/app/components/primer/beta/breadcrumbs.rb +2 -2
  16. data/app/components/primer/beta/text.rb +1 -1
  17. data/app/components/primer/border_box_component.rb +1 -1
  18. data/app/components/primer/box_component.rb +3 -2
  19. data/app/components/primer/button_component.html.erb +3 -9
  20. data/app/components/primer/button_component.rb +21 -2
  21. data/app/components/primer/button_group.rb +1 -1
  22. data/app/components/primer/clipboard_copy.rb +1 -1
  23. data/app/components/primer/close_button.rb +1 -1
  24. data/app/components/primer/component.rb +71 -0
  25. data/app/components/primer/counter_component.rb +1 -1
  26. data/app/components/primer/details_component.rb +1 -1
  27. data/app/components/primer/dropdown/menu.rb +1 -1
  28. data/app/components/primer/dropdown.html.erb +0 -1
  29. data/app/components/primer/dropdown.rb +1 -0
  30. data/app/components/primer/dropdown_menu_component.rb +1 -1
  31. data/app/components/primer/flash_component.rb +2 -1
  32. data/app/components/primer/flex_component.rb +16 -16
  33. data/app/components/primer/flex_item_component.rb +1 -1
  34. data/app/components/primer/hellip_button.rb +1 -1
  35. data/app/components/primer/hidden_text_expander.rb +1 -1
  36. data/app/components/primer/image.rb +1 -1
  37. data/app/components/primer/image_crop.rb +2 -1
  38. data/app/components/primer/layout_component.rb +1 -0
  39. data/app/components/primer/local_time.rb +1 -1
  40. data/app/components/primer/markdown.rb +1 -1
  41. data/app/components/primer/menu_component.rb +2 -1
  42. data/app/components/primer/navigation/tab_component.rb +1 -0
  43. data/app/components/primer/octicon_symbols_component.rb +2 -2
  44. data/app/components/primer/popover_component.rb +1 -1
  45. data/app/components/primer/progress_bar_component.rb +7 -6
  46. data/app/components/primer/spinner_component.rb +1 -1
  47. data/app/components/primer/subhead_component.rb +3 -1
  48. data/app/components/primer/tab_container_component.rb +1 -1
  49. data/app/components/primer/time_ago_component.rb +1 -1
  50. data/app/components/primer/timeline_item_component.rb +4 -3
  51. data/app/components/primer/tooltip.rb +1 -0
  52. data/lib/primer/classify/utilities.rb +26 -23
  53. data/lib/primer/classify/utilities.yml +192 -68
  54. data/lib/primer/classify.rb +92 -178
  55. data/lib/primer/view_components/linters/blankslate_api_migration.rb +11 -5
  56. data/lib/primer/view_components/version.rb +1 -1
  57. data/lib/rubocop/cop/primer/deprecated_layout_component.rb +30 -0
  58. data/lib/rubocop/cop/primer/primer_octicon.rb +1 -3
  59. data/lib/tasks/custom_utilities.yml +192 -0
  60. data/lib/tasks/docs.rake +1 -1
  61. data/lib/tasks/utilities.rake +6 -2
  62. data/static/classes.yml +14 -14
  63. data/static/constants.json +3 -3
  64. metadata +4 -4
  65. data/lib/primer/classify/cache.rb +0 -109
  66. data/lib/primer/classify/flex.rb +0 -111
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 61a72c86047d4820bb909bb7aba73505a1401868e362831ce3cfcd44f6c65da2
4
- data.tar.gz: cedb04ce42976410ad380e5d39e448fc2078f07fb3d26b3d2ce4e7d79141f6ea
3
+ metadata.gz: adce588d18cdf5a429f1cfbf22474252e3bfb96e929c7a991590069b38d7a8c6
4
+ data.tar.gz: d7c0ada1fa78d39d82b7beb6ef90b1900b923a4fcc0a401f5dc14a0f7e8d157e
5
5
  SHA512:
6
- metadata.gz: 714f04473ef45b3a80c4fcad50dbcd575a981c93b990f770844e903d561dc016cc88a94b09567deaa9954680add33581bc002c6f80b3a3590d2e64faf9397c63
7
- data.tar.gz: 8d982a43c2fd2a0d5fe32287c129c8d4559ae2441e3124f9f50857ccbf25e2a4a3b63426e6f5a1c24572d6d8804b90849a3e600e3680de3efdbc59c92de0293e
6
+ metadata.gz: 1d7a91266039e243395f6a630a1fa7838e1ca8cc6a038e66f22ad286e2b80e7c937408ce6f2f71bd3c2474680818d2a6fd0017a1ccc390432a83a331564309c8
7
+ data.tar.gz: 4f9d8101365c03c8fe01cd9b18da13ea6d602e93469511dd3d8b0792861f8d9f34a78b4a6137e6d80ebfa67c0387e46dd3fd391c6547cf232accc24536310b21
data/CHANGELOG.md CHANGED
@@ -30,6 +30,48 @@ The category for changes related to documentation, testing and tooling. Also, fo
30
30
 
31
31
  ## main
32
32
 
33
+ ## 0.0.62
34
+
35
+ ### New
36
+
37
+ * Add linter for tracking deprecated `LayoutComponent` callsites
38
+
39
+ *Josh Klina*
40
+
41
+ ### Updates
42
+
43
+ * Update `Button` to add `8px` spacing between icon, text and counter.
44
+
45
+ *Manuel Puyol*
46
+
47
+ * Update `BlankslateApiMigration` linter to support interpolations.
48
+
49
+ *Manuel Puyol*
50
+
51
+ * Change spacing in `Blankslate`:
52
+ * Between `description` and `primary_action` to `32px`.
53
+ * Between `primary_action` and `secondary_action` to `16px`.
54
+
55
+ *Manuel Puyol*
56
+
57
+ * Improve performance of `Classify#call`.
58
+
59
+ *Cameron Dutro*
60
+
61
+ ### Breaking Changes
62
+
63
+ * Add a warning to users if they try to use `tag:` parameters on a component where the tag is fixed
64
+
65
+ *Owen Niblock*
66
+
67
+ * Updating to @primer/css@19.0.0 and @primer/primitives@7.1.0. Which removes support for deprecated system color arguments
68
+
69
+ *Jon Rohan*
70
+
71
+ * Prevent `aria-label` to be used with `:div, :span, :p` tags without an explicit `role`.
72
+
73
+ *Manuel Puyol*
74
+
33
75
  ## 0.0.61
34
76
 
35
77
  ### New
@@ -48,7 +90,7 @@ The category for changes related to documentation, testing and tooling. Also, fo
48
90
 
49
91
  ### Updates
50
92
 
51
- * Bump Storybook version to include Skip to Content links for keyboard auditors
93
+ * Bump Storybook version to include Skip to Content links for keyboard auditors.
52
94
 
53
95
  *Katie Foster @inkblotty*
54
96
 
@@ -68,7 +110,7 @@ The category for changes related to documentation, testing and tooling. Also, fo
68
110
 
69
111
  ### Bug Fixes
70
112
 
71
- * Fix issue where tags were not self-closing when they are void elements
113
+ * Fix issue where tags were not self-closing when they are void elements.
72
114
 
73
115
  *Owen Niblock*
74
116
 
@@ -3,8 +3,7 @@
3
3
  module Primer
4
4
  module Alpha
5
5
  module BorderBox
6
- # BorderBox::Header: used inside the BorderBoxComponent to render its header slot
7
- # Optional title slot
6
+ # `BorderBox::Header` is used inside `BorderBox` to render its header slot.
8
7
  #
9
8
  # @accessibility When using `header.title`, set `tag` to one of `h1`, `h2`, `h3`, etc. based on what is appropriate for the page context. <%= link_to_heading_practices %>
10
9
  class Header < Primer::Component
@@ -7,9 +7,9 @@ module Primer
7
7
  DEFAULT_SCHEME = :default
8
8
  SCHEME_MAPPINGS = {
9
9
  DEFAULT_SCHEME => "",
10
- :primary => "btn-primary-mktg",
11
- :outline => "btn-outline-mktg",
12
- :transparent => "btn-transparent"
10
+ :primary => "btn-signup-mktg",
11
+ :outline => "btn-muted-mktg",
12
+ :transparent => "btn-subtle-mktg"
13
13
  }.freeze
14
14
  SCHEME_OPTIONS = SCHEME_MAPPINGS.keys
15
15
 
@@ -30,7 +30,7 @@ module Primer
30
30
  # <%= render(Primer::Alpha::ButtonMarketing.new(mr: 2)) { "Default" } %>
31
31
  # <%= render(Primer::Alpha::ButtonMarketing.new(scheme: :primary, mr: 2)) { "Primary" } %>
32
32
  # <%= render(Primer::Alpha::ButtonMarketing.new(scheme: :outline)) { "Outline" } %>
33
- # <div class="color-bg-canvas-inverse">
33
+ # <div class="color-bg-emphasis">
34
34
  # <%= render(Primer::Alpha::ButtonMarketing.new(scheme: :transparent)) { "Transparent" } %>
35
35
  # </div>
36
36
  #
@@ -101,7 +101,7 @@ module Primer
101
101
  # <% end %>
102
102
  #
103
103
  # @example Customizing the body
104
- # <%= render(Primer::Alpha::TabNav.new(label: "Default", body_arguments: { classes: "custom-class", border: true, border_color: :info })) do |c| %>
104
+ # <%= render(Primer::Alpha::TabNav.new(label: "Default", body_arguments: { classes: "custom-class", border: true, border_color: :accent_emphasis })) do |c| %>
105
105
  # <% c.tab(selected: true, href: "#") { "Tab 1" }%>
106
106
  # <% c.tab(href: "#") { "Tab 2" } %>
107
107
  # <% c.tab(href: "#") { "Tab 3" } %>
@@ -66,11 +66,11 @@ module Primer
66
66
  @align = EXTRA_ALIGN_DEFAULT
67
67
  @wrapper_arguments = wrapper_arguments
68
68
 
69
- @system_arguments = system_arguments
69
+ @system_arguments = deny_tag_argument(**system_arguments)
70
70
  @system_arguments[:tag] = :div
71
71
  @system_arguments[:classes] = tab_nav_classes(@system_arguments[:classes])
72
72
 
73
- @body_arguments = body_arguments
73
+ @body_arguments = deny_tag_argument(**body_arguments)
74
74
  @body_arguments[:tag] = :ul
75
75
  @body_arguments[:classes] = tab_nav_body_classes(@body_arguments[:classes])
76
76
 
@@ -5,6 +5,7 @@ module Primer
5
5
  # Use `UnderlineNav` to style navigation links with a minimal
6
6
  # underlined selected state, typically placed at the top
7
7
  # of the page.
8
+ #
8
9
  # For panel navigation, use <%= link_to_component(Primer::Alpha::UnderlinePanels) %> instead.
9
10
  #
10
11
  # @accessibility
@@ -102,7 +103,7 @@ module Primer
102
103
  # <% end %>
103
104
  #
104
105
  # @example Customizing the body
105
- # <%= render(Primer::Alpha::UnderlineNav.new(label: "Default", body_arguments: { classes: "custom-class", border: true, border_color: :info })) do |c| %>
106
+ # <%= render(Primer::Alpha::UnderlineNav.new(label: "Default", body_arguments: { classes: "custom-class", border: true, border_color: :accent_emphasis })) do |c| %>
106
107
  # <% c.tab(selected: true, href: "#") { "Tab 1" }%>
107
108
  # <% c.tab(href: "#") { "Tab 2" } %>
108
109
  # <% c.tab(href: "#") { "Tab 3" } %>
@@ -64,11 +64,11 @@ module Primer
64
64
  @align = fetch_or_fallback(ALIGN_OPTIONS, align, ALIGN_DEFAULT)
65
65
  @wrapper_arguments = wrapper_arguments
66
66
 
67
- @system_arguments = system_arguments
67
+ @system_arguments = deny_tag_argument(**system_arguments)
68
68
  @system_arguments[:tag] = :div
69
69
  @system_arguments[:classes] = underline_nav_classes(@system_arguments[:classes], @align)
70
70
 
71
- @body_arguments = body_arguments
71
+ @body_arguments = deny_tag_argument(**body_arguments)
72
72
  @body_arguments[:tag] = :ul
73
73
  @body_arguments[:classes] = underline_nav_body_classes(@body_arguments[:classes])
74
74
 
@@ -72,14 +72,14 @@ module Primer
72
72
  #
73
73
  # | Name | Type | Description |
74
74
  # | :- | :- | :- |
75
- # | `align_items` | Symbol | <%= one_of(Primer::Classify::Flex::ALIGN_ITEMS_VALUES) %> |
76
- # | `align_self` | Symbol | <%= one_of(Primer::Classify::Flex::ALIGN_SELF_VALUES) %> |
77
- # | `direction` | Symbol | <%= one_of(Primer::Classify::Flex::DIRECTION_VALUES) %> |
78
- # | `flex` | Integer, Symbol | <%= one_of(Primer::Classify::Flex::FLEX_VALUES) %> |
75
+ # | `align_items` | Symbol | <%= one_of(Primer::Classify::FLEX_ALIGN_ITEMS_VALUES) %> |
76
+ # | `align_self` | Symbol | <%= one_of(Primer::Classify::FLEX_ALIGN_SELF_VALUES) %> |
77
+ # | `direction` | Symbol | <%= one_of(Primer::Classify::FLEX_DIRECTION_VALUES) %> |
78
+ # | `flex` | Integer, Symbol | <%= one_of(Primer::Classify::FLEX_VALUES) %> |
79
79
  # | `flex_grow` | Integer | To enable, set to `0`. |
80
80
  # | `flex_shrink` | Integer | To enable, set to `0`. |
81
- # | `flex_wrap` | Symbol | <%= one_of(Primer::Classify::Flex::WRAP_MAPPINGS.keys) %> |
82
- # | `justify_content` | Symbol | <%= one_of(Primer::Classify::Flex::JUSTIFY_CONTENT_VALUES) %> |
81
+ # | `flex_wrap` | Symbol | <%= one_of(Primer::Classify::FLEX_WRAP_MAPPINGS.keys) %> |
82
+ # | `justify_content` | Symbol | <%= one_of(Primer::Classify::FLEX_JUSTIFY_CONTENT_VALUES) %> |
83
83
  #
84
84
  # ## Grid
85
85
  #
@@ -151,42 +151,14 @@ module Primer
151
151
  # | test_selector | String | Adds `data-test-selector='given value'` in non-Production environments for testing purposes. |
152
152
  def initialize(tag:, classes: nil, **system_arguments)
153
153
  @tag = tag
154
- @system_arguments = system_arguments
155
154
 
156
- raise ArgumentError, "`class` is an invalid argument. Use `classes` instead." if system_arguments.key?(:class) && !Rails.env.production?
157
-
158
- if (denylist = system_arguments[:system_arguments_denylist])
159
- if raise_on_invalid_options? && !ENV["PRIMER_WARNINGS_DISABLED"]
160
- # Convert denylist from:
161
- # { [:p, :pt] => "message" } to:
162
- # { p: "message", pt: "message" }
163
- unpacked_denylist =
164
- denylist.each_with_object({}) do |(keys, value), memo|
165
- keys.each { |key| memo[key] = value }
166
- end
167
-
168
- violations = unpacked_denylist.keys & @system_arguments.keys
169
-
170
- if violations.any?
171
- message = "Found #{violations.count} #{'violation'.pluralize(violations)}:"
172
- violations.each do |violation|
173
- message += "\n The #{violation} system argument is not allowed here. #{unpacked_denylist[violation]}"
174
- end
175
-
176
- raise(ArgumentError, message)
177
- end
178
- end
179
-
180
- # Remove :system_arguments_denylist key and any denied keys from system arguments
181
- @system_arguments.except!(:system_arguments_denylist)
182
- @system_arguments.except!(*denylist.keys.flatten)
183
- end
155
+ @system_arguments = validate_arguments(tag: tag, **system_arguments)
184
156
 
185
157
  @result = Primer::Classify.call(**@system_arguments.merge(classes: classes))
186
158
 
187
159
  @system_arguments[:"data-view-component"] = true
188
160
  # Filter out Primer keys so they don't get assigned as HTML attributes
189
- @content_tag_args = add_test_selector(@system_arguments).except(*Primer::Classify::VALID_KEYS)
161
+ @content_tag_args = add_test_selector(@system_arguments).except(*Primer::Classify::Utilities::UTILITIES.keys)
190
162
  end
191
163
 
192
164
  def call
@@ -20,7 +20,7 @@ module Primer
20
20
  # @param disabled [Boolean] Whether the item is disabled.
21
21
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
22
22
  def initialize(value:, selected: false, disabled: false, **system_arguments)
23
- @system_arguments = system_arguments
23
+ @system_arguments = deny_tag_argument(**system_arguments)
24
24
  @system_arguments[:tag] = :li
25
25
  @system_arguments[:role] = :option
26
26
  @system_arguments[:"data-autocomplete-value"] = value
@@ -19,6 +19,7 @@ module Primer
19
19
  #
20
20
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
21
21
  renders_one :label, lambda { |**system_arguments|
22
+ deny_tag_argument(**system_arguments)
22
23
  system_arguments[:for] = @input_id
23
24
  system_arguments[:tag] = :label
24
25
  Primer::BaseComponent.new(**system_arguments)
@@ -47,6 +48,7 @@ module Primer
47
48
  #
48
49
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
49
50
  renders_one :results, lambda { |**system_arguments|
51
+ deny_tag_argument(**system_arguments)
50
52
  system_arguments[:tag] = :ul
51
53
  system_arguments[:id] = @list_id
52
54
  system_arguments[:classes] = class_names(
@@ -110,7 +112,7 @@ module Primer
110
112
 
111
113
  system_arguments.delete(:"aria-label") && system_arguments[:aria]&.delete(:label)
112
114
 
113
- @system_arguments = system_arguments
115
+ @system_arguments = deny_tag_argument(**system_arguments)
114
116
  @system_arguments[:tag] = "auto-complete"
115
117
  @system_arguments[:src] = src
116
118
  @system_arguments[:for] = list_id
@@ -133,7 +135,7 @@ module Primer
133
135
  # @param type [Symbol] <%= one_of(Primer::Beta::AutoComplete::Input::TYPE_OPTIONS) %>
134
136
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
135
137
  def initialize(type: DEFAULT_TYPE, **system_arguments)
136
- @system_arguments = system_arguments
138
+ @system_arguments = deny_tag_argument(**system_arguments)
137
139
  @system_arguments[:tag] = :input
138
140
 
139
141
  @aria_label = system_arguments[:"aria-label"]
@@ -53,7 +53,7 @@ module Primer
53
53
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
54
54
  def initialize(src:, alt:, size: DEFAULT_SIZE, shape: DEFAULT_SHAPE, href: nil, **system_arguments)
55
55
  @href = href
56
- @system_arguments = system_arguments
56
+ @system_arguments = deny_tag_argument(**system_arguments)
57
57
  @system_arguments[:tag] = :img
58
58
  @system_arguments[:src] = src
59
59
  @system_arguments[:alt] = alt
@@ -7,9 +7,9 @@
7
7
 
8
8
  <%= primary_action %>
9
9
  <% if secondary_action.present? %>
10
- <p>
10
+ <div class="mt-3">
11
11
  <%= secondary_action %>
12
- </p>
12
+ </div>
13
13
  <% end %>
14
14
  <% end %>
15
15
  <% end %>
@@ -50,6 +50,7 @@ module Primer
50
50
  # @param tag [String] <%= one_of(Primer::HeadingComponent::TAG_OPTIONS) %>
51
51
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
52
52
  renders_one :heading, lambda { |tag:, **system_arguments|
53
+ deny_tag_argument(**system_arguments)
53
54
  system_arguments[:tag] = tag
54
55
  system_arguments[:mb] = 1
55
56
  system_arguments[:classes] = class_names("h2", system_arguments[:classes])
@@ -64,7 +65,8 @@ module Primer
64
65
  #
65
66
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
66
67
  renders_one :description, lambda { |**system_arguments|
67
- system_arguments[:tag] = :p
68
+ deny_tag_argument(**system_arguments)
69
+ system_arguments[:tag] = :div
68
70
 
69
71
  Primer::BaseComponent.new(**system_arguments)
70
72
  }
@@ -77,9 +79,10 @@ module Primer
77
79
  # @param href [String] URL to be used for the primary action.
78
80
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
79
81
  renders_one :primary_action, lambda { |href:, **system_arguments|
82
+ deny_tag_argument(**system_arguments)
80
83
  system_arguments[:tag] = :a
81
84
  system_arguments[:href] = href
82
- system_arguments[:my] = 3
85
+ system_arguments[:mt] = 5
83
86
  system_arguments[:variant] = :medium
84
87
  system_arguments[:scheme] ||= :primary
85
88
 
@@ -211,7 +214,7 @@ module Primer
211
214
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
212
215
  def initialize(narrow: false, spacious: false, border: false, **system_arguments)
213
216
  @border = border
214
- @system_arguments = system_arguments
217
+ @system_arguments = deny_tag_argument(**system_arguments)
215
218
  @system_arguments[:tag] = :div
216
219
  @system_arguments[:classes] = class_names(
217
220
  @system_arguments[:classes],
@@ -40,7 +40,7 @@ module Primer
40
40
  #
41
41
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
42
42
  def initialize(**system_arguments)
43
- @system_arguments = system_arguments
43
+ @system_arguments = deny_tag_argument(**system_arguments)
44
44
  @system_arguments[:tag] = :nav
45
45
  @system_arguments[:aria] = ARIA_LABEL
46
46
  @system_arguments[:system_arguments_denylist] = ARGS_DENYLIST
@@ -57,7 +57,7 @@ module Primer
57
57
 
58
58
  def initialize(href:, **system_arguments)
59
59
  @href = href
60
- @system_arguments = system_arguments
60
+ @system_arguments = deny_tag_argument(**system_arguments)
61
61
  @selected = false
62
62
 
63
63
  @system_arguments[:tag] = :li
@@ -10,7 +10,7 @@ module Primer
10
10
 
11
11
  # @example Default
12
12
  # <%= render(Primer::Beta::Text.new(tag: :p, font_weight: :bold)) { "Bold Text" } %>
13
- # <%= render(Primer::Beta::Text.new(tag: :p, color: :text_danger)) { "Danger Text" } %>
13
+ # <%= render(Primer::Beta::Text.new(tag: :p, color: :danger)) { "Danger Text" } %>
14
14
  #
15
15
  # @param tag [Symbol]
16
16
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
@@ -127,7 +127,7 @@ module Primer
127
127
  # @param padding [Symbol] <%= one_of(Primer::BorderBoxComponent::PADDING_MAPPINGS.keys) %>
128
128
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
129
129
  def initialize(padding: DEFAULT_PADDING, **system_arguments)
130
- @system_arguments = system_arguments
130
+ @system_arguments = deny_tag_argument(**system_arguments)
131
131
  @system_arguments[:tag] = :div
132
132
  @system_arguments[:classes] = class_names(
133
133
  "Box",
@@ -9,11 +9,12 @@ module Primer
9
9
  # <%= render(Primer::BoxComponent.new) { "Your content here" } %>
10
10
  #
11
11
  # @example Color and padding
12
- # <%= render(Primer::BoxComponent.new(bg: :tertiary, p: 3)) { "Hello world" } %>
12
+ # <%= render(Primer::BoxComponent.new(bg: :subtle, p: 3)) { "Hello world" } %>
13
13
  #
14
14
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
15
15
  def initialize(**system_arguments)
16
- @system_arguments = system_arguments
16
+ @system_arguments = deny_tag_argument(**system_arguments)
17
+
17
18
  @system_arguments[:tag] = :div
18
19
  end
19
20
 
@@ -1,9 +1,3 @@
1
- <%= render Primer::BaseButton.new(**@system_arguments) do %>
2
- <%= icon %>
3
- <%= content %>
4
- <%= counter %>
5
-
6
- <% if @caret %>
7
- <%= primer_octicon("triangle-down") %>
8
- <% end %>
9
- <% end %>
1
+ <%= render Primer::BaseButton.new(**@system_arguments) do -%>
2
+ <%= icon %><%= trimmed_content %><%= counter %><%= primer_octicon("triangle-down", mr: -1) if @caret %>
3
+ <% end -%>
@@ -28,12 +28,20 @@ module Primer
28
28
  # Icon to be rendered in the button.
29
29
  #
30
30
  # @param system_arguments [Hash] Same arguments as <%= link_to_component(Primer::OcticonComponent) %>.
31
- renders_one :icon, Primer::OcticonComponent
31
+ renders_one :icon, lambda { |**system_arguments|
32
+ system_arguments[:mr] = 2
33
+
34
+ Primer::OcticonComponent.new(**system_arguments)
35
+ }
32
36
 
33
37
  # Counter to be rendered in the button.
34
38
  #
35
39
  # @param system_arguments [Hash] Same arguments as <%= link_to_component(Primer::CounterComponent) %>.
36
- renders_one :counter, Primer::CounterComponent
40
+ renders_one :counter, lambda { |**system_arguments|
41
+ system_arguments[:ml] = 2
42
+
43
+ Primer::CounterComponent.new(**system_arguments)
44
+ }
37
45
 
38
46
  # @example Schemes
39
47
  # <%= render(Primer::ButtonComponent.new) { "Default" } %>
@@ -111,5 +119,16 @@ module Primer
111
119
  def link?
112
120
  @scheme == LINK_SCHEME
113
121
  end
122
+
123
+ def trimmed_content
124
+ return if content.blank?
125
+
126
+ trimmed_content = content.strip
127
+
128
+ return trimmed_content unless content.html_safe?
129
+
130
+ # strip unsets `html_safe`, so we have to set it back again to guarantee that HTML blocks won't break
131
+ trimmed_content.html_safe # rubocop:disable Rails/OutputSafety
132
+ end
114
133
  end
115
134
  end
@@ -45,7 +45,7 @@ module Primer
45
45
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
46
46
  def initialize(variant: Primer::ButtonComponent::DEFAULT_VARIANT, **system_arguments)
47
47
  @variant = variant
48
- @system_arguments = system_arguments
48
+ @system_arguments = deny_tag_argument(**system_arguments)
49
49
  @system_arguments[:tag] = :div
50
50
 
51
51
  @system_arguments[:classes] = class_names(
@@ -25,7 +25,7 @@ module Primer
25
25
  # @param for [String] Element id from where to get the copied value.
26
26
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
27
27
  def initialize(value: nil, **system_arguments)
28
- @system_arguments = system_arguments
28
+ @system_arguments = deny_tag_argument(**system_arguments)
29
29
  @value = value
30
30
 
31
31
  validate!
@@ -19,7 +19,7 @@ module Primer
19
19
  # @param type [Symbol] <%= one_of(Primer::CloseButton::TYPE_OPTIONS) %>
20
20
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
21
21
  def initialize(type: DEFAULT_TYPE, **system_arguments)
22
- @system_arguments = system_arguments
22
+ @system_arguments = deny_tag_argument(**system_arguments)
23
23
  @system_arguments[:tag] = :button
24
24
  @system_arguments[:block] = false
25
25
  @system_arguments[:type] = fetch_or_fallback(TYPE_OPTIONS, type, DEFAULT_TYPE)
@@ -14,6 +14,8 @@ module Primer
14
14
  include Status::Dsl
15
15
  include Audited::Dsl
16
16
 
17
+ INVALID_ARIA_LABEL_TAGS = [:div, :span, :p].freeze
18
+
17
19
  private
18
20
 
19
21
  def raise_on_invalid_options?
@@ -42,5 +44,74 @@ module Primer
42
44
  def silence_deprecations?
43
45
  Rails.application.config.primer_view_components.silence_deprecations
44
46
  end
47
+
48
+ def check_denylist(denylist = [], **arguments)
49
+ if should_raise_error?
50
+
51
+ # Convert denylist from:
52
+ # { [:p, :pt] => "message" } to:
53
+ # { p: "message", pt: "message" }
54
+ unpacked_denylist =
55
+ denylist.each_with_object({}) do |(keys, value), memo|
56
+ keys.each { |key| memo[key] = value }
57
+ end
58
+
59
+ violations = unpacked_denylist.keys & arguments.keys
60
+
61
+ if violations.any?
62
+ message = "Found #{violations.count} #{'violation'.pluralize(violations)}:"
63
+ violations.each do |violation|
64
+ message += "\n The #{violation} argument is not allowed here. #{unpacked_denylist[violation]}"
65
+ end
66
+
67
+ raise(ArgumentError, message)
68
+ end
69
+ end
70
+
71
+ arguments
72
+ end
73
+
74
+ def validate_arguments(tag:, denylist_name: :system_arguments_denylist, **arguments)
75
+ deny_single_argument(:class, "Use `classes` instead.", **arguments)
76
+
77
+ if (denylist = arguments[denylist_name])
78
+ check_denylist(denylist, **arguments)
79
+
80
+ # Remove :system_arguments_denylist key and any denied keys from system arguments
81
+ arguments.except!(denylist_name)
82
+ arguments.except!(*denylist.keys.flatten)
83
+ end
84
+
85
+ deny_aria_label(tag: tag, arguments: arguments)
86
+
87
+ arguments
88
+ end
89
+
90
+ def deny_single_argument(key, help_text, **arguments)
91
+ raise ArgumentError, "`#{key}` is an invalid argument. #{help_text}" \
92
+ if should_raise_error? && arguments.key?(key)
93
+
94
+ arguments.except!(key)
95
+ end
96
+
97
+ def deny_aria_label(tag:, arguments:)
98
+ return arguments.except!(:skip_aria_label_check) if arguments[:skip_aria_label_check]
99
+ return if arguments[:role]
100
+ return unless aria(:label, arguments)
101
+ return unless INVALID_ARIA_LABEL_TAGS.include?(tag)
102
+
103
+ raise ArgumentError, "Don't use `aria-label` on `#{tag}` elements. See https://www.tpgi.com/short-note-on-aria-label-aria-labelledby-and-aria-describedby/" if should_raise_error?
104
+
105
+ arguments.except!(:"aria-label")
106
+ arguments[:aria] = arguments[:aria].except!(:label) if arguments[:aria]
107
+ end
108
+
109
+ def deny_tag_argument(**arguments)
110
+ deny_single_argument(:tag, "This component has a fixed tag.", **arguments)
111
+ end
112
+
113
+ def should_raise_error?
114
+ raise_on_invalid_options? && !ENV["PRIMER_WARNINGS_DISABLED"]
115
+ end
45
116
  end
46
117
  end
@@ -51,7 +51,7 @@ module Primer
51
51
  @hide_if_zero = hide_if_zero
52
52
  @text = text
53
53
  @round = round
54
- @system_arguments = system_arguments
54
+ @system_arguments = deny_tag_argument(**system_arguments)
55
55
 
56
56
  @has_limit = !@limit.nil?
57
57
  @system_arguments[:title] = title
@@ -52,7 +52,7 @@ module Primer
52
52
  # @param reset [Boolean] Defatuls to false. If set to true, it will remove the default caret and remove style from the summary element
53
53
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
54
54
  def initialize(overlay: NO_OVERLAY, reset: false, **system_arguments)
55
- @system_arguments = system_arguments
55
+ @system_arguments = deny_tag_argument(**system_arguments)
56
56
  @system_arguments[:tag] = :details
57
57
  @system_arguments[:classes] = class_names(
58
58
  system_arguments[:classes],
@@ -33,7 +33,7 @@ module Primer
33
33
  @direction = direction
34
34
  @as = fetch_or_fallback(AS_OPTIONS, as, AS_DEFAULT)
35
35
 
36
- @system_arguments = system_arguments
36
+ @system_arguments = deny_tag_argument(**system_arguments)
37
37
  @system_arguments[:tag] = "details-menu"
38
38
  @system_arguments[:role] = "menu"
39
39
 
@@ -1,7 +1,6 @@
1
1
  <%= render(Primer::DetailsComponent.new(**@system_arguments)) do |c| %>
2
2
  <% c.summary(**@button_arguments) do %>
3
3
  <%= button %>
4
- <% if @with_caret %><div class="dropdown-caret"></div><% end %>
5
4
  <% end %>
6
5
 
7
6
  <% c.body do %>
@@ -9,6 +9,7 @@ module Primer
9
9
  renders_one :button, lambda { |**system_arguments, &block|
10
10
  @button_arguments = system_arguments
11
11
  @button_arguments[:button] = true
12
+ @button_arguments[:caret] = @with_caret
12
13
 
13
14
  view_context.capture { block&.call }
14
15
  }
@@ -42,7 +42,7 @@ module Primer
42
42
  def initialize(direction: DIRECTION_DEFAULT, scheme: SCHEME_DEFAULT, header: nil, **system_arguments)
43
43
  @header = header
44
44
  @direction = direction
45
- @system_arguments = system_arguments
45
+ @system_arguments = deny_tag_argument(**system_arguments)
46
46
 
47
47
  @system_arguments[:tag] = "details-menu"
48
48
  @system_arguments[:role] = "menu"
@@ -9,6 +9,7 @@ module Primer
9
9
  #
10
10
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
11
11
  renders_one :action, lambda { |**system_arguments|
12
+ deny_tag_argument(**system_arguments)
12
13
  system_arguments[:tag] = :div
13
14
  system_arguments[:classes] = class_names(system_arguments[:classes], "flash-action")
14
15
 
@@ -54,7 +55,7 @@ module Primer
54
55
  def initialize(full: false, spacious: false, dismissible: false, icon: nil, scheme: DEFAULT_SCHEME, **system_arguments)
55
56
  @icon = icon
56
57
  @dismissible = dismissible
57
- @system_arguments = system_arguments
58
+ @system_arguments = deny_tag_argument(**system_arguments)
58
59
  @system_arguments[:tag] = :div
59
60
  @system_arguments[:classes] = class_names(
60
61
  @system_arguments[:classes],