primer_view_components 0.0.61 → 0.0.62

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 (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],