primer_view_components 0.0.43 → 0.0.47

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 (81) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +220 -3
  3. data/app/assets/javascripts/primer_view_components.js +1 -1
  4. data/app/assets/javascripts/primer_view_components.js.map +1 -1
  5. data/app/components/primer/alpha/button_marketing.rb +70 -0
  6. data/app/components/primer/avatar_stack_component.rb +9 -3
  7. data/app/components/primer/base_component.rb +52 -23
  8. data/app/components/primer/beta/auto_complete.rb +159 -0
  9. data/app/components/primer/beta/auto_complete/auto_complete.d.ts +1 -0
  10. data/app/components/primer/{auto_complete → beta/auto_complete}/auto_complete.html.erb +1 -0
  11. data/app/components/primer/beta/auto_complete/auto_complete.js +1 -0
  12. data/app/components/primer/{auto_complete → beta/auto_complete}/auto_complete.ts +0 -0
  13. data/app/components/primer/beta/auto_complete/item.rb +44 -0
  14. data/app/components/primer/beta/avatar.rb +77 -0
  15. data/app/components/primer/beta/text.rb +27 -0
  16. data/app/components/primer/blankslate_component.rb +2 -1
  17. data/app/components/primer/border_box_component.rb +3 -0
  18. data/app/components/primer/button_component.rb +3 -2
  19. data/app/components/primer/clipboard_copy.rb +25 -7
  20. data/app/components/primer/component.rb +4 -0
  21. data/app/components/primer/details_component.rb +18 -3
  22. data/app/components/primer/dropdown.d.ts +1 -0
  23. data/app/components/primer/{dropdown_component.html.erb → dropdown.html.erb} +2 -1
  24. data/app/components/primer/dropdown.js +1 -0
  25. data/app/components/primer/dropdown.rb +149 -0
  26. data/app/components/primer/dropdown.ts +1 -0
  27. data/app/components/primer/dropdown/menu.d.ts +1 -0
  28. data/app/components/primer/dropdown/menu.html.erb +25 -0
  29. data/app/components/primer/dropdown/menu.js +1 -0
  30. data/app/components/primer/dropdown/menu.rb +99 -0
  31. data/app/components/primer/dropdown/menu.ts +1 -0
  32. data/app/components/primer/heading_component.rb +1 -1
  33. data/app/components/primer/icon_button.rb +1 -1
  34. data/app/components/primer/image_crop.rb +1 -1
  35. data/app/components/primer/markdown.rb +9 -9
  36. data/app/components/primer/menu_component.rb +7 -3
  37. data/app/components/primer/navigation/tab_component.rb +6 -6
  38. data/app/components/primer/octicon_component.rb +3 -2
  39. data/app/components/primer/popover_component.rb +6 -3
  40. data/app/components/primer/primer.d.ts +2 -1
  41. data/app/components/primer/primer.js +2 -1
  42. data/app/components/primer/primer.ts +2 -1
  43. data/app/components/primer/spinner_component.rb +2 -0
  44. data/app/components/primer/tab_nav_component.rb +5 -3
  45. data/app/components/primer/timeline_item_component.rb +2 -2
  46. data/app/components/primer/tooltip.rb +1 -1
  47. data/app/components/primer/truncate.rb +5 -0
  48. data/app/components/primer/underline_nav_component.rb +10 -4
  49. data/{app/lib → lib}/primer/classify.rb +16 -33
  50. data/{app/lib → lib}/primer/classify/cache.rb +6 -40
  51. data/{app/lib → lib}/primer/classify/flex.rb +0 -0
  52. data/{app/lib → lib}/primer/classify/functional_background_colors.rb +2 -0
  53. data/{app/lib → lib}/primer/classify/functional_border_colors.rb +2 -0
  54. data/{app/lib → lib}/primer/classify/functional_colors.rb +0 -0
  55. data/{app/lib → lib}/primer/classify/functional_text_colors.rb +2 -0
  56. data/{app/lib → lib}/primer/classify/grid.rb +0 -0
  57. data/lib/primer/classify/utilities.rb +148 -0
  58. data/lib/primer/classify/utilities.yml +1271 -0
  59. data/lib/primer/view_components.rb +1 -0
  60. data/lib/primer/view_components/linters/argument_mappers/button.rb +82 -0
  61. data/lib/primer/view_components/linters/argument_mappers/conversion_error.rb +10 -0
  62. data/lib/primer/view_components/linters/argument_mappers/system_arguments.rb +47 -0
  63. data/lib/primer/view_components/linters/button_component_migration_counter.rb +24 -1
  64. data/lib/primer/view_components/linters/flash_component_migration_counter.rb +1 -1
  65. data/lib/primer/view_components/linters/helpers.rb +137 -18
  66. data/lib/primer/view_components/statuses.rb +14 -0
  67. data/lib/primer/view_components/version.rb +1 -1
  68. data/lib/tasks/docs.rake +179 -110
  69. data/lib/tasks/utilities.rake +105 -0
  70. data/lib/yard/docs_helper.rb +13 -3
  71. data/static/statuses.json +9 -7
  72. metadata +41 -27
  73. data/app/components/primer/auto_complete.rb +0 -100
  74. data/app/components/primer/auto_complete/item.rb +0 -42
  75. data/app/components/primer/avatar_component.rb +0 -75
  76. data/app/components/primer/button_marketing_component.rb +0 -68
  77. data/app/components/primer/dropdown/menu_component.html.erb +0 -12
  78. data/app/components/primer/dropdown/menu_component.rb +0 -46
  79. data/app/components/primer/dropdown_component.rb +0 -73
  80. data/app/components/primer/text_component.rb +0 -25
  81. data/app/lib/primer/classify/spacing.rb +0 -63
@@ -0,0 +1,159 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Beta
5
+ # Use `AutoComplete` to provide a user with a list of selectable suggestions that appear when they type into the
6
+ # input field. This list is populated by server search results.
7
+ # @accessibility
8
+ # Always set an accessible label to help the user interact with the component.
9
+ #
10
+ # * Set the `label` slot to render a visible label. Alternatively, associate an existing visible text element
11
+ # as a label by setting `aria-labelledby`.
12
+ # * If you must use a non-visible label, set `:"aria-label"` on `AutoComplete` and Primer
13
+ # will apply it to the correct elements. However, please note that a visible label should almost
14
+ # always be used unless there is compelling reason not to. A placeholder is not a label.
15
+ class AutoComplete < Primer::Component
16
+ status :beta
17
+
18
+ # Optionally render a visible label. See <%= link_to_accessibility %>
19
+ #
20
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
21
+ renders_one :label, lambda { |**system_arguments|
22
+ system_arguments[:for] = @input_id
23
+ system_arguments[:tag] = :label
24
+ Primer::BaseComponent.new(**system_arguments)
25
+ }
26
+
27
+ # Required input used to search for results
28
+ #
29
+ # @param type [Symbol] <%= one_of(Primer::Beta::AutoComplete::Input::TYPE_OPTIONS) %>
30
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
31
+ renders_one :input, lambda { |**system_arguments|
32
+ aria_label = system_arguments[:"aria-label"] || system_arguments.dig(:aria, :label) || @aria_label
33
+ if aria_label.present?
34
+ system_arguments[:"aria-label"] = aria_label
35
+ system_arguments[:aria]&.delete(:label)
36
+ end
37
+
38
+ name = system_arguments[:name] || @input_id
39
+ Input.new(id: @input_id, name: name, **system_arguments)
40
+ }
41
+
42
+ # Optional icon to be rendered before the input. Has the same arguments as <%= link_to_component(Primer::OcticonComponent) %>.
43
+ #
44
+ renders_one :icon, Primer::OcticonComponent
45
+
46
+ # Customizable results list.
47
+ #
48
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
49
+ renders_one :results, lambda { |**system_arguments|
50
+ system_arguments[:tag] = :ul
51
+ system_arguments[:id] = @list_id
52
+ system_arguments[:classes] = class_names(
53
+ "autocomplete-results",
54
+ system_arguments[:classes]
55
+ )
56
+
57
+ aria_label = system_arguments[:"aria-label"] || system_arguments.dig(:aria, :label) || @aria_label
58
+ system_arguments[:"aria-label"] = aria_label if aria_label.present?
59
+ system_arguments[:aria]&.delete(:label)
60
+
61
+ Primer::BaseComponent.new(**system_arguments)
62
+ }
63
+
64
+ # @example Default
65
+ # <%= render(Primer::Beta::AutoComplete.new(src: "/auto_complete", input_id: "fruits-input-1", list_id: "fruits-popup-1", position: :relative)) do |c| %>
66
+ # <% c.label(classes:"").with_content("Fruits") %>
67
+ # <% c.input(type: :text) %>
68
+ # <% end %>
69
+ #
70
+ # @example With `aria-label`
71
+ # <%= render(Primer::Beta::AutoComplete.new("aria-label": "Fruits", src: "/auto_complete", input_id: "fruits-input-2", list_id: "fruits-popup-2", position: :relative)) do |c| %>
72
+ # <% c.input(type: :text) %>
73
+ # <% end %>
74
+ #
75
+ # @example With `aria-labelledby`
76
+ # <%= render(Primer::HeadingComponent.new(tag: :h2, id: "search-1")) { "Search" } %>
77
+ # <%= render(Primer::Beta::AutoComplete.new(src: "/auto_complete", input_id: "fruits-input-3", list_id: "fruits-popup-2", position: :relative)) do |c| %>
78
+ # <% c.input("aria-labelledby": "search-1") %>
79
+ # <% end %>
80
+ #
81
+ # @example With custom classes for the results
82
+ # <%= render(Primer::Beta::AutoComplete.new(src: "/auto_complete", input_id: "fruits-input-4", list_id: "fruits-popup-3", position: :relative)) do |c| %>
83
+ # <% c.label(classes:"").with_content("Fruits") %>
84
+ # <% c.input(type: :text) %>
85
+ # <% c.results(classes: "custom-class") do %>
86
+ # <%= render(Primer::Beta::AutoComplete::Item.new(selected: true, value: "apple")) do |c| %>
87
+ # Apple
88
+ # <% end %>
89
+ # <%= render(Primer::Beta::AutoComplete::Item.new(value: "orange")) do |c| %>
90
+ # Orange
91
+ # <% end %>
92
+ # <% end %>
93
+ # <% end %>
94
+ #
95
+ # @example With Icon
96
+ # <%= render(Primer::Beta::AutoComplete.new(src: "/auto_complete", list_id: "fruits-popup-4", input_id: "fruits-input-4", position: :relative)) do |c| %>
97
+ # <% c.label(classes:"").with_content("Fruits") %>
98
+ # <% c.input(type: :text) %>
99
+ # <% c.icon(icon: :search) %>
100
+ # <% end %>
101
+ #
102
+ # @param src [String] The route to query.
103
+ # @param input_id [String] Id of the input element.
104
+ # @param list_id [String] Id of the list element.
105
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
106
+ def initialize(src:, list_id:, input_id:, **system_arguments)
107
+ @list_id = list_id
108
+ @input_id = input_id
109
+ @aria_label = system_arguments[:"aria-label"] || system_arguments.dig(:aria, :label)
110
+
111
+ system_arguments.delete(:"aria-label") && system_arguments[:aria]&.delete(:label)
112
+
113
+ @system_arguments = system_arguments
114
+ @system_arguments[:tag] = "auto-complete"
115
+ @system_arguments[:src] = src
116
+ @system_arguments[:for] = list_id
117
+ end
118
+
119
+ # add `results` without needing to explicitly call it in the view
120
+ def before_render
121
+ raise ArgumentError, "Missing `input` slot" if input.blank?
122
+ raise ArgumentError, "Accessible label is required." if label.blank? && input.missing_label?
123
+
124
+ results(classes: "") unless results
125
+ end
126
+
127
+ # This component is part of `Primer::Beta::AutoCompleteComponent` and should not be
128
+ # used as a standalone component.
129
+ class Input < Primer::Component
130
+ DEFAULT_TYPE = :text
131
+ TYPE_OPTIONS = [DEFAULT_TYPE, :search].freeze
132
+
133
+ # @param type [Symbol] <%= one_of(Primer::Beta::AutoComplete::Input::TYPE_OPTIONS) %>
134
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
135
+ def initialize(type: DEFAULT_TYPE, **system_arguments)
136
+ @system_arguments = system_arguments
137
+ @system_arguments[:tag] = :input
138
+
139
+ @aria_label = system_arguments[:"aria-label"]
140
+ @aria_labelledby = system_arguments[:"aria-labelledby"] || system_arguments.dig(:aria, :labelledby)
141
+
142
+ @system_arguments[:type] = fetch_or_fallback(TYPE_OPTIONS, type, DEFAULT_TYPE)
143
+ @system_arguments[:classes] = class_names(
144
+ "form-control",
145
+ system_arguments[:classes]
146
+ )
147
+ end
148
+
149
+ def missing_label?
150
+ @aria_label.blank? && @aria_labelledby.blank?
151
+ end
152
+
153
+ def call
154
+ render(Primer::BaseComponent.new(**@system_arguments))
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1 @@
1
+ import '@github/auto-complete-element';
@@ -1,3 +1,4 @@
1
+ <%= label %>
1
2
  <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
3
  <%= input %>
3
4
  <%= icon %>
@@ -0,0 +1 @@
1
+ import '@github/auto-complete-element';
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Beta
5
+ class AutoComplete
6
+ # Use `AutoCompleteItem` to list results of an auto-completed search.
7
+ class Item < Primer::Component
8
+ status :beta
9
+
10
+ # @example Default
11
+ # <%= render(Primer::Beta::AutoComplete::Item.new(selected: true, value: "value")) do |c| %>
12
+ # Selected
13
+ # <% end %>
14
+ # <%= render(Primer::Beta::AutoComplete::Item.new(value: "value")) do |c| %>
15
+ # Not selected
16
+ # <% end %>
17
+ #
18
+ # @param value [String] Value of the item.
19
+ # @param selected [Boolean] Whether the item is selected.
20
+ # @param disabled [Boolean] Whether the item is disabled.
21
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
22
+ def initialize(value:, selected: false, disabled: false, **system_arguments)
23
+ @system_arguments = system_arguments
24
+ @system_arguments[:tag] = :li
25
+ @system_arguments[:role] = :option
26
+ @system_arguments[:"data-autocomplete-value"] = value
27
+
28
+ @system_arguments[:"aria-selected"] = true if selected
29
+ @system_arguments[:"aria-disabled"] = true if disabled
30
+
31
+ @system_arguments[:classes] = class_names(
32
+ "autocomplete-item",
33
+ system_arguments[:classes],
34
+ "disabled" => disabled
35
+ )
36
+ end
37
+
38
+ def call
39
+ render(Primer::BaseComponent.new(**@system_arguments)) { content }
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Beta
5
+ # `Avatar` can be used to represent users and organizations on GitHub.
6
+ #
7
+ # - Use the default round avatar for users, and the `square` argument
8
+ # for organizations or any other non-human avatars.
9
+ # - By default, `Avatar` will render a static `<img>`. To have `Avatar` function as a link, set the `href` which will wrap the `<img>` in a `<a>`.
10
+ # - Set `size` to update the height and width of the `Avatar` in pixels.
11
+ # - To stack multiple avatars together, use <%= link_to_component(Primer::AvatarStackComponent) %>.
12
+ #
13
+ # @accessibility
14
+ # Images should have text alternatives that describe the information or function represented.
15
+ # If the avatar functions as a link, provide alt text that helps convey the function. For instance,
16
+ # if `Avatar` is a link to a user profile, the alt attribute should be `@kittenuser profile`
17
+ # rather than `@kittenuser`.
18
+ # [Learn more about best image practices (WAI Images)](https://www.w3.org/WAI/tutorials/images/)
19
+ class Avatar < Primer::Component
20
+ status :beta
21
+
22
+ SMALL_THRESHOLD = 24
23
+
24
+ # @example Default
25
+ # <%= render(Primer::Beta::Avatar.new(src: "http://placekitten.com/200/200", alt: "@kittenuser")) %>
26
+ #
27
+ # @example Square
28
+ # <%= render(Primer::Beta::Avatar.new(src: "http://placekitten.com/200/200", alt: "@kittenuser", square: true)) %>
29
+ #
30
+ # @example Link
31
+ # <%= render(Primer::Beta::Avatar.new(href: "#", src: "http://placekitten.com/200/200", alt: "@kittenuser profile")) %>
32
+ #
33
+ # @example With size
34
+ # <%= render(Primer::Beta::Avatar.new(src: "http://placekitten.com/200/200", alt: "@kittenuser", size: 16)) %>
35
+ # <%= render(Primer::Beta::Avatar.new(src: "http://placekitten.com/200/200", alt: "@kittenuser", size: 20)) %>
36
+ # <%= render(Primer::Beta::Avatar.new(src: "http://placekitten.com/200/200", alt: "@kittenuser", size: 24)) %>
37
+ # <%= render(Primer::Beta::Avatar.new(src: "http://placekitten.com/200/200", alt: "@kittenuser", size: 28)) %>
38
+ # <%= render(Primer::Beta::Avatar.new(src: "http://placekitten.com/200/200", alt: "@kittenuser", size: 32)) %>
39
+ # <%= render(Primer::Beta::Avatar.new(src: "http://placekitten.com/200/200", alt: "@kittenuser", size: 36)) %>
40
+ #
41
+ # @param src [String] The source url of the avatar image.
42
+ # @param alt [String] Passed through to alt on img tag.
43
+ # @param size [Integer] Adds the avatar-small class if less than 24.
44
+ # @param square [Boolean] Used to create a square avatar.
45
+ # @param href [String] The URL to link to. If used, component will be wrapped by an `<a>` tag.
46
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
47
+ def initialize(src:, alt:, size: 20, square: false, href: nil, **system_arguments)
48
+ @href = href
49
+ @system_arguments = system_arguments
50
+ @system_arguments[:tag] = :img
51
+ @system_arguments[:src] = src
52
+ @system_arguments[:alt] = alt
53
+ @system_arguments[:size] = size
54
+ @system_arguments[:height] = size
55
+ @system_arguments[:width] = size
56
+
57
+ @system_arguments[:classes] = class_names(
58
+ system_arguments[:classes],
59
+ "avatar",
60
+ "avatar-small" => size < SMALL_THRESHOLD,
61
+ "circle" => !square,
62
+ "lh-0" => href # Addresses an overflow issue with linked avatars
63
+ )
64
+ end
65
+
66
+ def call
67
+ if @href
68
+ render(Primer::LinkComponent.new(href: @href, classes: @system_arguments[:classes])) do
69
+ render(Primer::BaseComponent.new(**@system_arguments.except(:classes))) { content }
70
+ end
71
+ else
72
+ render(Primer::BaseComponent.new(**@system_arguments)) { content }
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Beta
5
+ # `Text` is a wrapper component that will apply typography styles to the text inside.
6
+ class Text < Primer::Component
7
+ status :beta
8
+
9
+ DEFAULT_TAG = :span
10
+
11
+ # @example Default
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" } %>
14
+ #
15
+ # @param tag [Symbol]
16
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
17
+ def initialize(tag: DEFAULT_TAG, **system_arguments)
18
+ @system_arguments = system_arguments
19
+ @system_arguments[:tag] = tag
20
+ end
21
+
22
+ def call
23
+ render(Primer::BaseComponent.new(**@system_arguments)) { content }
24
+ end
25
+ end
26
+ end
27
+ end
@@ -95,7 +95,7 @@ module Primer
95
95
  # @param title [String] Text that appears in a larger bold font.
96
96
  # @param title_tag [Symbol] HTML tag to use for title.
97
97
  # @param icon [Symbol] Octicon icon to use at top of component.
98
- # @param icon_size [Symbol] <%= one_of(Primer::OcticonComponent::SIZE_MAPPINGS) %>
98
+ # @param icon_size [Symbol] <%= one_of(Primer::OcticonComponent::SIZE_MAPPINGS, sort: false) %>
99
99
  # @param image_src [String] Image to display.
100
100
  # @param image_alt [String] Alt text for image.
101
101
  # @param description [String] Text that appears below the title. Typically a whole sentence.
@@ -107,6 +107,7 @@ module Primer
107
107
  # @param narrow [Boolean] Adds a maximum width.
108
108
  # @param large [Boolean] Increases the font size.
109
109
  # @param spacious [Boolean] Adds extra padding.
110
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
110
111
  def initialize(
111
112
  title: "",
112
113
  title_tag: :h3,
@@ -11,6 +11,7 @@ module Primer
11
11
  :condensed => "Box--condensed",
12
12
  :spacious => "Box--spacious"
13
13
  }.freeze
14
+ PADDING_SUGGESTION = "Perhaps you could consider using :padding options of #{PADDING_MAPPINGS.keys.to_sentence}?"
14
15
 
15
16
  # Optional Header.
16
17
  #
@@ -111,6 +112,8 @@ module Primer
111
112
  PADDING_MAPPINGS[fetch_or_fallback(PADDING_MAPPINGS.keys, padding, DEFAULT_PADDING)],
112
113
  system_arguments[:classes]
113
114
  )
115
+
116
+ @system_arguments[:system_arguments_denylist] = { [:p, :pt, :pb, :pr, :pl] => PADDING_SUGGESTION }
114
117
  end
115
118
 
116
119
  def render?
@@ -78,11 +78,12 @@ module Primer
78
78
  #
79
79
  # @param scheme [Symbol] <%= one_of(Primer::ButtonComponent::SCHEME_OPTIONS) %>
80
80
  # @param variant [Symbol] <%= one_of(Primer::ButtonComponent::VARIANT_OPTIONS) %>
81
- # @param tag [Symbol] <%= one_of(Primer::BaseButton::TAG_OPTIONS) %>
82
- # @param type [Symbol] <%= one_of(Primer::BaseButton::TYPE_OPTIONS) %>
81
+ # @param tag [Symbol] (Primer::BaseButton::DEFAULT_TAG) <%= one_of(Primer::BaseButton::TAG_OPTIONS) %>
82
+ # @param type [Symbol] (Primer::BaseButton::DEFAULT_TYPE) <%= one_of(Primer::BaseButton::TYPE_OPTIONS) %>
83
83
  # @param group_item [Boolean] Whether button is part of a ButtonGroup.
84
84
  # @param block [Boolean] Whether button is full-width with `display: block`.
85
85
  # @param caret [Boolean] Whether or not to render a caret.
86
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
86
87
  def initialize(
87
88
  scheme: DEFAULT_SCHEME,
88
89
  variant: DEFAULT_VARIANT,
@@ -2,25 +2,43 @@
2
2
 
3
3
  module Primer
4
4
  # Use `ClipboardCopy` to copy element text content or input values to the clipboard.
5
+ #
6
+ # @accessibility
7
+ # Always set an accessible label to help the user interact with the component.
5
8
  class ClipboardCopy < Primer::Component
6
9
  status :alpha
7
10
 
8
11
  # @example Default
9
- # <%= render(Primer::ClipboardCopy.new(value: "Text to copy", label: "Copy text to the system clipboard")) %>
12
+ # <%= render(Primer::ClipboardCopy.new(value: "Text to copy", "aria-label": "Copy text to the system clipboard")) %>
10
13
  #
11
14
  # @example With text instead of icons
12
- # <%= render(Primer::ClipboardCopy.new(value: "Text to copy", label: "Copy text to the system clipboard")) do %>
15
+ # <%= render(Primer::ClipboardCopy.new(value: "Text to copy", "aria-label": "Copy text to the system clipboard")) do %>
13
16
  # Click to copy!
14
17
  # <% end %>
15
18
  #
16
- # @param label [String] String that will be read to screenreaders when the component is focused
17
- # @param value [String] Text to copy into the users clipboard when they click the component
19
+ # @example Copying from an element
20
+ # <%= render(Primer::ClipboardCopy.new(for: "blob-path", "aria-label": "Copy text to the system clipboard")) %>
21
+ # <div id="blob-path">src/index.js</div>
22
+ #
23
+ # @param aria-label [String] String that will be read to screenreaders when the component is focused
24
+ # @param value [String] Text to copy into the users clipboard when they click the component.
25
+ # @param for [String] Element id from where to get the copied value.
18
26
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
19
- def initialize(label:, value:, **system_arguments)
27
+ def initialize(value: nil, **system_arguments)
20
28
  @system_arguments = system_arguments
29
+ @value = value
30
+
31
+ validate!
32
+
21
33
  @system_arguments[:tag] = "clipboard-copy"
22
- @system_arguments[:value] = value
23
- @system_arguments[:"aria-label"] = label
34
+ @system_arguments[:value] = value if value.present?
35
+ end
36
+
37
+ private
38
+
39
+ def validate!
40
+ validate_aria_label
41
+ raise ArgumentError, "Must provide either `value` or `for`" if @value.nil? && @system_arguments[:for].nil?
24
42
  end
25
43
  end
26
44
  end
@@ -15,6 +15,10 @@ module Primer
15
15
 
16
16
  private
17
17
 
18
+ def force_system_arguments?
19
+ Rails.application.config.primer_view_components.force_system_arguments
20
+ end
21
+
18
22
  def deprecated_component_warning(new_class: nil, version: nil)
19
23
  return if Rails.env.production? || silence_deprecations?
20
24
 
@@ -5,6 +5,8 @@ module Primer
5
5
  class DetailsComponent < Primer::Component
6
6
  status :beta
7
7
 
8
+ BODY_TAG_DEFAULT = :div
9
+ BODY_TAG_OPTIONS = [:ul, :"details-menu", :"details-dialog", BODY_TAG_DEFAULT].freeze
8
10
  NO_OVERLAY = :none
9
11
  OVERLAY_MAPPINGS = {
10
12
  NO_OVERLAY => "",
@@ -14,7 +16,7 @@ module Primer
14
16
 
15
17
  # Use the Summary slot as a trigger to reveal the content.
16
18
  #
17
- # @param button [Boolean] Whether to render the Summary as a button or not.
19
+ # @param button [Boolean] (true) Whether to render the Summary as a button or not.
18
20
  # @param kwargs [Hash] The same arguments as <%= link_to_system_arguments_docs %>.
19
21
  renders_one :summary, lambda { |button: true, **system_arguments|
20
22
  system_arguments[:tag] = :summary
@@ -27,12 +29,25 @@ module Primer
27
29
 
28
30
  # Use the Body slot as the main content to be shown when triggered by the Summary.
29
31
  #
32
+ # @param tag [Symbol] (Primer::DetailsComponent::BODY_TAG_DEFAULT) <%= one_of(Primer::DetailsComponent::BODY_TAG_OPTIONS) %>
30
33
  # @param kwargs [Hash] The same arguments as <%= link_to_system_arguments_docs %>.
31
- renders_one :body, lambda { |**system_arguments|
32
- system_arguments[:tag] ||= :div
34
+ renders_one :body, lambda { |tag: BODY_TAG_DEFAULT, **system_arguments|
35
+ system_arguments[:tag] = fetch_or_fallback(BODY_TAG_OPTIONS, tag, BODY_TAG_DEFAULT)
36
+
33
37
  Primer::BaseComponent.new(**system_arguments)
34
38
  }
35
39
 
40
+ # @example Default
41
+ #
42
+ # <%= render Primer::DetailsComponent.new do |c| %>
43
+ # <% c.summary do %>
44
+ # Summary
45
+ # <% end %>
46
+ # <% c.body do %>
47
+ # Body
48
+ # <% end %>
49
+ # <% end %>
50
+ #
36
51
  # @param overlay [Symbol] Dictates the type of overlay to render with. <%= one_of(Primer::DetailsComponent::OVERLAY_MAPPINGS.keys) %>
37
52
  # @param reset [Boolean] Defatuls to false. If set to true, it will remove the default caret and remove style from the summary element
38
53
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>