primer_view_components 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  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/assets/styles/primer_view_components.css +2 -2
  6. data/app/assets/styles/primer_view_components.css.map +1 -1
  7. data/app/components/primer/alpha/action_list/divider.rb +1 -1
  8. data/app/components/primer/alpha/action_list/heading.html.erb +2 -2
  9. data/app/components/primer/alpha/action_list/heading.rb +9 -5
  10. data/app/components/primer/alpha/action_list.css +1 -1
  11. data/app/components/primer/alpha/action_list.css.json +1 -0
  12. data/app/components/primer/alpha/action_list.css.map +1 -1
  13. data/app/components/primer/alpha/action_list.html.erb +1 -0
  14. data/app/components/primer/alpha/action_list.pcss +5 -0
  15. data/app/components/primer/alpha/action_list.rb +14 -11
  16. data/app/components/primer/alpha/dialog.rb +4 -0
  17. data/app/components/primer/alpha/nav_list/divider.rb +14 -0
  18. data/app/components/primer/alpha/nav_list/group.html.erb +7 -0
  19. data/app/components/primer/alpha/nav_list/group.rb +24 -11
  20. data/app/components/primer/alpha/nav_list/item.rb +4 -0
  21. data/app/components/primer/alpha/nav_list.d.ts +0 -1
  22. data/app/components/primer/alpha/nav_list.html.erb +9 -4
  23. data/app/components/primer/alpha/nav_list.js +3 -4
  24. data/app/components/primer/alpha/nav_list.rb +87 -10
  25. data/app/components/primer/alpha/nav_list.ts +3 -2
  26. data/app/components/primer/alpha/segmented_control.css +1 -1
  27. data/app/components/primer/alpha/segmented_control.css.json +2 -2
  28. data/app/components/primer/alpha/segmented_control.css.map +1 -1
  29. data/app/components/primer/alpha/segmented_control.pcss +10 -8
  30. data/app/components/primer/alpha/text_field.css +1 -1
  31. data/app/components/primer/alpha/text_field.css.json +11 -11
  32. data/app/components/primer/alpha/text_field.css.map +1 -1
  33. data/app/components/primer/alpha/text_field.pcss +2 -2
  34. data/app/components/primer/beta/button.css +1 -1
  35. data/app/components/primer/beta/button.css.json +2 -0
  36. data/app/components/primer/beta/button.css.map +1 -1
  37. data/app/components/primer/beta/button.pcss +9 -0
  38. data/app/components/primer/component.rb +3 -96
  39. data/app/lib/primer/attributes_helper.rb +105 -0
  40. data/lib/primer/forms/text_field.rb +6 -0
  41. data/lib/primer/view_components/version.rb +1 -1
  42. data/previews/primer/alpha/nav_list_preview/trailing_action.html.erb +10 -10
  43. data/previews/primer/alpha/nav_list_preview.rb +37 -16
  44. data/previews/primer/beta/button_preview/trailing_counter.html.erb +11 -0
  45. data/previews/primer/beta/button_preview.rb +15 -0
  46. data/previews/primer/box_preview.rb +28 -0
  47. data/static/arguments.json +22 -12
  48. data/static/audited_at.json +1 -0
  49. data/static/classes.json +3 -0
  50. data/static/constants.json +3 -0
  51. data/static/info_arch.json +136 -19
  52. data/static/previews.json +38 -0
  53. data/static/statuses.json +1 -0
  54. metadata +7 -2
@@ -16,6 +16,7 @@ module Primer
16
16
  include ViewComponent::PolymorphicSlots
17
17
  end
18
18
 
19
+ include AttributesHelper
19
20
  include ClassNameHelper
20
21
  include FetchOrFallbackHelper
21
22
  include TestSelectorHelper
@@ -25,15 +26,13 @@ module Primer
25
26
  include Audited::Dsl
26
27
 
27
28
  INVALID_ARIA_LABEL_TAGS = [:div, :span, :p].freeze
28
- PLURAL_ARIA_ATTRIBUTES = %i[describedby labelledby].freeze
29
- PLURAL_DATA_ATTRIBUTES = %i[target targets].freeze
30
29
 
31
30
  def self.deprecated?
32
31
  status == :deprecated
33
32
  end
34
33
 
35
- def self.generate_id
36
- "#{name.demodulize.underscore.dasherize}-#{SecureRandom.uuid}"
34
+ def self.generate_id(base_name: name.demodulize.underscore.dasherize)
35
+ "#{base_name}-#{SecureRandom.uuid}"
37
36
  end
38
37
 
39
38
  private
@@ -56,98 +55,6 @@ module Primer
56
55
  ActiveSupport::Deprecation.warn(message)
57
56
  end
58
57
 
59
- def aria(val, system_arguments)
60
- system_arguments[:"aria-#{val}"] || system_arguments.dig(:aria, val.to_sym)
61
- end
62
-
63
- # Merges hashes that contain "aria-*" keys and nested aria: hashes. Removes keys from
64
- # each hash and returns them in the new hash.
65
- #
66
- # Eg. merge_aria({ "aria-disabled": "true" }, { aria: { invalid: "true" } })
67
- # => { disabled: "true", invalid: "true" }
68
- #
69
- # Certain aria attributes can contain multiple values separated by spaces. merge_aria
70
- # will combine these plural attributes into a composite string.
71
- #
72
- # Eg. merge_aria({ "aria-labelledby": "foo" }, { aria: { labelledby: "bar" } })
73
- # => { labelledby: "foo bar" }
74
- #
75
- # It's designed to be used to normalize and merge aria information from system_arguments
76
- # hashes. Consider using this pattern in component initializers:
77
- #
78
- # @system_arguments[:aria] = merge_aria(
79
- # @system_arguments,
80
- # { aria: { labelled_by: id } }
81
- # )
82
- def merge_aria(*hashes)
83
- merge_prefixed_attribute_hashes(
84
- *hashes, prefix: :aria, plural_keys: PLURAL_ARIA_ATTRIBUTES
85
- )
86
- end
87
-
88
- # Merges hashes that contain "data-*" keys and nested data: hashes. Removes keys from
89
- # each hash and returns them in the new hash.
90
- #
91
- # Eg. merge_data({ "data-foo": "true" }, { data: { bar: "true" } })
92
- # => { foo: "true", bar: "true" }
93
- #
94
- # Certain data attributes can contain multiple values separated by spaces. merge_data
95
- # will combine these plural attributes into a composite string.
96
- #
97
- # Eg. merge_data({ "data-target": "foo" }, { data: { target: "bar" } })
98
- # => { target: "foo bar" }
99
- #
100
- # It's designed to be used to normalize and merge data information from system_arguments
101
- # hashes. Consider using this pattern in component initializers:
102
- #
103
- # @system_arguments[:data] = merge_aria(
104
- # @system_arguments,
105
- # { data: { foo: "bar" } }
106
- # )
107
- def merge_data(*hashes)
108
- merge_prefixed_attribute_hashes(
109
- *hashes, prefix: :data, plural_keys: PLURAL_DATA_ATTRIBUTES
110
- )
111
- end
112
-
113
- def merge_prefixed_attribute_hashes(*hashes, prefix:, plural_keys:)
114
- {}.tap do |result|
115
- hashes.each do |hash|
116
- next unless hash
117
-
118
- prefix_hash = hash.delete(prefix) || {}
119
-
120
- prefix_hash.each_pair do |key, val|
121
- result[key] =
122
- if plural_keys.include?(key)
123
- [*(result[key] || "").split, val].join(" ").strip
124
- else
125
- val
126
- end
127
- end
128
-
129
- hash.delete_if do |key, val|
130
- key_s = key.to_s
131
-
132
- if key.start_with?("#{prefix}-")
133
- bare_key = key_s.sub("#{prefix}-", "").to_sym
134
-
135
- result[bare_key] =
136
- if plural_keys.include?(bare_key)
137
- [*(result[bare_key] || "").split, val].join(" ").strip
138
- else
139
- val
140
- end
141
-
142
- true
143
- else
144
- false
145
- end
146
- end
147
- end
148
- end
149
- end
150
-
151
58
  def validate_aria_label
152
59
  aria_label = aria("label", @system_arguments)
153
60
  aria_labelledby = aria("labelledby", @system_arguments)
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ # :nodoc:
5
+ module AttributesHelper
6
+ PLURAL_ARIA_ATTRIBUTES = %i[describedby labelledby].freeze
7
+ PLURAL_DATA_ATTRIBUTES = %i[target targets].freeze
8
+
9
+ def aria(val, system_arguments)
10
+ system_arguments[:"aria-#{val}"] || system_arguments.dig(:aria, val.to_sym)
11
+ end
12
+
13
+ def data(val, system_arguments)
14
+ system_arguments[:"data-#{val}"] || system_arguments.dig(:data, val.to_sym)
15
+ end
16
+
17
+ # Merges hashes that contain "aria-*" keys and nested aria: hashes. Removes keys from
18
+ # each hash and returns them in the new hash.
19
+ #
20
+ # Eg. merge_aria({ "aria-disabled": "true" }, { aria: { invalid: "true" } })
21
+ # => { disabled: "true", invalid: "true" }
22
+ #
23
+ # Certain aria attributes can contain multiple values separated by spaces. merge_aria
24
+ # will combine these plural attributes into a composite string.
25
+ #
26
+ # Eg. merge_aria({ "aria-labelledby": "foo" }, { aria: { labelledby: "bar" } })
27
+ # => { labelledby: "foo bar" }
28
+ #
29
+ # It's designed to be used to normalize and merge aria information from system_arguments
30
+ # hashes. Consider using this pattern in component initializers:
31
+ #
32
+ # @system_arguments[:aria] = merge_aria(
33
+ # @system_arguments,
34
+ # { aria: { labelled_by: id } }
35
+ # )
36
+ def merge_aria(*hashes)
37
+ merge_prefixed_attribute_hashes(
38
+ *hashes, prefix: :aria, plural_keys: PLURAL_ARIA_ATTRIBUTES
39
+ )
40
+ end
41
+
42
+ # Merges hashes that contain "data-*" keys and nested data: hashes. Removes keys from
43
+ # each hash and returns them in the new hash.
44
+ #
45
+ # Eg. merge_data({ "data-foo": "true" }, { data: { bar: "true" } })
46
+ # => { foo: "true", bar: "true" }
47
+ #
48
+ # Certain data attributes can contain multiple values separated by spaces. merge_data
49
+ # will combine these plural attributes into a composite string.
50
+ #
51
+ # Eg. merge_data({ "data-target": "foo" }, { data: { target: "bar" } })
52
+ # => { target: "foo bar" }
53
+ #
54
+ # It's designed to be used to normalize and merge data information from system_arguments
55
+ # hashes. Consider using this pattern in component initializers:
56
+ #
57
+ # @system_arguments[:data] = merge_aria(
58
+ # @system_arguments,
59
+ # { data: { foo: "bar" } }
60
+ # )
61
+ def merge_data(*hashes)
62
+ merge_prefixed_attribute_hashes(
63
+ *hashes, prefix: :data, plural_keys: PLURAL_DATA_ATTRIBUTES
64
+ )
65
+ end
66
+
67
+ def merge_prefixed_attribute_hashes(*hashes, prefix:, plural_keys:)
68
+ {}.tap do |result|
69
+ hashes.each do |hash|
70
+ next unless hash
71
+
72
+ prefix_hash = hash.delete(prefix) || {}
73
+
74
+ prefix_hash.each_pair do |key, val|
75
+ result[key] =
76
+ if plural_keys.include?(key)
77
+ [*(result[key] || "").split, val].join(" ").strip
78
+ else
79
+ val
80
+ end
81
+ end
82
+
83
+ hash.delete_if do |key, val|
84
+ key_s = key.to_s
85
+
86
+ if key.start_with?("#{prefix}-")
87
+ bare_key = key_s.sub("#{prefix}-", "").to_sym
88
+
89
+ result[bare_key] =
90
+ if plural_keys.include?(bare_key)
91
+ [*(result[bare_key] || "").split, val].join(" ").strip
92
+ else
93
+ val
94
+ end
95
+
96
+ true
97
+ else
98
+ false
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -6,6 +6,11 @@ module Primer
6
6
  class TextField < BaseComponent
7
7
  delegate :builder, :form, to: :@input
8
8
 
9
+ INPUT_WRAP_SIZE = {
10
+ small: "FormControl-input-wrap--small",
11
+ large: "FormControl-input-wrap--large"
12
+ }.freeze
13
+
9
14
  def initialize(input:)
10
15
  @input = input
11
16
 
@@ -17,6 +22,7 @@ module Primer
17
22
  @field_wrap_arguments = {
18
23
  class: class_names(
19
24
  "FormControl-input-wrap",
25
+ INPUT_WRAP_SIZE[input.size],
20
26
  "FormControl-input-wrap--trailingAction": @input.show_clear_button?,
21
27
  "FormControl-input-wrap--leadingVisual": @input.leading_visual?
22
28
  ),
@@ -6,7 +6,7 @@ module Primer
6
6
  module VERSION
7
7
  MAJOR = 0
8
8
  MINOR = 1
9
- PATCH = 7
9
+ PATCH = 8
10
10
 
11
11
  STRING = [MAJOR, MINOR, PATCH].join(".")
12
12
  end
@@ -1,19 +1,19 @@
1
- <%= render(Primer::Alpha::NavList.new) do |list| %>
1
+ <%= render(Primer::Alpha::NavList.new(aria: { label: "Workflow results" })) do |list| %>
2
2
  <% list.with_group do |group| %>
3
- <%= group.with_heading(title: "Shopping list") %>
4
- <% group.with_item(label: "Bread", href: "/list/1") do |item| %>
5
- <%= item.with_trailing_action(icon: :plus, aria: { label: "Activate alert" }, name: "bread_button") %>
3
+ <% group.with_heading(title: "Workflows") %>
4
+ <% group.with_item(label: "Build and Test", href: "/workflows/1") do |item| %>
5
+ <%= item.with_trailing_action(icon: :sync, aria: { label: "Build and test: re-run workflow" }, name: "build_and_test_button") %>
6
6
  <% end %>
7
- <% group.with_item(label: "Cheese", href: "/list/2") do |item| %>
8
- <%= item.with_trailing_action(icon: :plus, aria: { label: "Activate alert" }, name: "cheese_button") %>
7
+ <% group.with_item(label: "Publish", href: "/workflows/2") do |item| %>
8
+ <%= item.with_trailing_action(icon: :sync, aria: { label: "Publish: re-run workflow" }, name: "publish_button") %>
9
9
  <% end %>
10
10
  <% end %>
11
11
  <% end %>
12
12
 
13
13
  <script type="text/javascript" data-eval="true">
14
- const breadButton = document.querySelector("[name=bread_button]")
15
- breadButton.addEventListener("click", () => alert("You selected bread."))
14
+ const breadButton = document.querySelector("[name=build_and_test_button]")
15
+ breadButton.addEventListener("click", () => alert("The 'Build and Test' workflow will be re-run."))
16
16
 
17
- const cheeseButton = document.querySelector("[name=cheese_button]")
18
- cheeseButton.addEventListener("click", () => alert("You selected cheese."))
17
+ const cheeseButton = document.querySelector("[name=publish_button]")
18
+ cheeseButton.addEventListener("click", () => alert("The 'Publish' workflow will be re-run."))
19
19
  </script>
@@ -6,13 +6,11 @@ module Primer
6
6
  class NavListPreview < ViewComponent::Preview
7
7
  # @label Playground
8
8
  def playground
9
- render(Primer::Alpha::NavList.new(selected_item_id: :code_review_limits)) do |list|
10
- list.with_group do |group|
11
- group.with_heading(title: "Repository settings")
9
+ render(Primer::Alpha::NavList.new(aria: { label: "Repository settings" }, selected_item_id: :code_review_limits)) do |list|
10
+ list.with_heading(title: "Repository settings")
12
11
 
13
- group.with_item(label: "General", href: "/general") do |item|
14
- item.with_leading_visual_icon(icon: :gear)
15
- end
12
+ list.with_item(label: "General", href: "/general") do |item|
13
+ item.with_leading_visual_icon(icon: :gear)
16
14
  end
17
15
 
18
16
  list.with_group do |group|
@@ -35,13 +33,17 @@ module Primer
35
33
 
36
34
  # @label Default
37
35
  def default
38
- render(Primer::Alpha::NavList.new(selected_item_id: :code_review_limits)) do |list|
39
- list.with_group do |group|
40
- group.with_heading(title: "Repository settings")
36
+ render(Primer::Alpha::NavList.new(aria: { label: "Repository settings" }, selected_item_id: :code_review_limits)) do |list|
37
+ list.with_heading(title: "Repository settings")
41
38
 
42
- group.with_item(label: "General", href: "/general") do |item|
43
- item.with_leading_visual_icon(icon: :gear)
44
- end
39
+ list.with_item(label: "General", href: "/general") do |item|
40
+ item.with_leading_visual_icon(icon: :gear)
41
+ end
42
+
43
+ list.with_divider
44
+
45
+ list.with_item(label: "Settings", href: "/settings") do |item|
46
+ item.with_leading_visual_icon(icon: :beaker)
45
47
  end
46
48
 
47
49
  list.with_group do |group|
@@ -62,21 +64,40 @@ module Primer
62
64
  end
63
65
  end
64
66
 
67
+ # @label Top-level items
68
+ #
69
+ def top_level_items
70
+ render(Primer::Alpha::NavList.new(aria: { label: "Account settings" })) do |list|
71
+ list.with_heading(title: "Account settings")
72
+
73
+ list.with_item(label: "General", href: "/general") do |item|
74
+ item.with_leading_visual_icon(icon: :gear)
75
+ end
76
+
77
+ list.with_item(label: "Billing", href: "/billing") do |item|
78
+ item.with_leading_visual_icon(icon: :"credit-card")
79
+ end
80
+
81
+ list.with_item(label: "Change password", href: "/change_password") do |item|
82
+ item.with_leading_visual_icon(icon: :key)
83
+ end
84
+ end
85
+ end
86
+
65
87
  # @label Show more item
66
88
  def show_more_item
67
- render(Primer::Alpha::NavList.new) do |list|
89
+ render(Primer::Alpha::NavList.new(aria: { label: "My favorite foods" })) do |list|
68
90
  list.with_group do |group|
69
91
  group.with_heading(title: "My favorite foods")
70
92
  group.with_item(label: "Popplers", href: "/foods/popplers")
71
93
  group.with_item(label: "Slurm", href: "/foods/slurm")
72
- group.with_show_more_item(label: "Show more", src: "/nav_list_items", pages: 2)
94
+ group.with_show_more_item(label: "Show more foods", src: UrlHelpers.nav_list_items_path, pages: 2)
73
95
  end
74
96
  end
75
97
  end
76
98
 
77
99
  # @label Trailing action
78
- def trailing_action
79
- end
100
+ def trailing_action; end
80
101
  end
81
102
  end
82
103
  end
@@ -0,0 +1,11 @@
1
+ <%= render(Primer::Beta::Button.new(
2
+ scheme: :primary,
3
+ size: :medium,
4
+ block: block,
5
+ id: id,
6
+ align_content: align_content
7
+ )) do |component| %>
8
+ <% component.with_leading_visual_icon(icon: :star) %>
9
+ <% component.with_trailing_visual_counter(count: 15) %>
10
+ Button
11
+ <% end %>
@@ -266,6 +266,21 @@ module Primer
266
266
  })
267
267
  end
268
268
 
269
+ # @label Trailing Counter
270
+ # @param block toggle
271
+ # @param align_content select [center, start]
272
+ def trailing_counter(
273
+ block: false,
274
+ id: "button-preview",
275
+ align_content: :center
276
+ )
277
+ render_with_template(locals: {
278
+ block: block,
279
+ id: id,
280
+ align_content: align_content
281
+ })
282
+ end
283
+
269
284
  # @label With tooltip
270
285
  # @param scheme select [default, primary, danger, invisible, link]
271
286
  # @param size select [small, medium]
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ # @label Box
5
+ class BoxPreview < ViewComponent::Preview
6
+ # @label Playground
7
+ #
8
+ # @param content [String] text
9
+ def playground(content: "Playground")
10
+ render(Primer::Box.new) { content }
11
+ end
12
+
13
+ # @label Default
14
+ def default(content: "Default")
15
+ render(Primer::Box.new) { content }
16
+ end
17
+
18
+ # @label Border
19
+ def border(content: "Box with border")
20
+ render(Primer::Box.new(border: true, p: 3)) { content }
21
+ end
22
+
23
+ # @label Border Bottom
24
+ def border_bottom(content: "Box with bottom border")
25
+ render(Primer::Box.new(border: :bottom, p: 3)) { content }
26
+ end
27
+ end
28
+ end
@@ -98,12 +98,6 @@
98
98
  "source": "https://github.com/primer/view_components/tree/main/app/components/primer/alpha/action_list/heading.rb",
99
99
  "lookbook": "https://primer.style/view-components/lookbook/inspect/primer/alpha/action_list/heading/default/",
100
100
  "parameters": [
101
- {
102
- "name": "id",
103
- "type": "String",
104
- "default": "`self.class.generate_id`",
105
- "description": "The group's identifier (ID attribute in HTML)."
106
- },
107
101
  {
108
102
  "name": "title",
109
103
  "type": "String",
@@ -128,12 +122,6 @@
128
122
  "default": "`:subtle`",
129
123
  "description": "Display a background color if scheme is `filled`."
130
124
  },
131
- {
132
- "name": "tag",
133
- "type": "Integer",
134
- "default": "N/A",
135
- "description": "Semantic tag for the heading."
136
- },
137
125
  {
138
126
  "name": "system_arguments",
139
127
  "type": "Hash",
@@ -1396,6 +1384,28 @@
1396
1384
  }
1397
1385
  ]
1398
1386
  },
1387
+ {
1388
+ "component": "NavList::Divider",
1389
+ "status": "alpha",
1390
+ "a11y_reviewed": false,
1391
+ "short_name": "NavListDivider",
1392
+ "source": "https://github.com/primer/view_components/tree/main/app/components/primer/alpha/nav_list/divider.rb",
1393
+ "lookbook": "https://primer.style/view-components/lookbook/inspect/primer/alpha/nav_list/divider/default/",
1394
+ "parameters": [
1395
+ {
1396
+ "name": "scheme",
1397
+ "type": "Symbol",
1398
+ "default": "`:subtle`",
1399
+ "description": "Display a background color if scheme is `filled`."
1400
+ },
1401
+ {
1402
+ "name": "system_arguments",
1403
+ "type": "Hash",
1404
+ "default": "N/A",
1405
+ "description": "[System arguments](/system-arguments)"
1406
+ }
1407
+ ]
1408
+ },
1399
1409
  {
1400
1410
  "component": "NavList::Group",
1401
1411
  "status": "alpha",
@@ -31,6 +31,7 @@
31
31
  "Primer::Alpha::Menu": "",
32
32
  "Primer::Alpha::MultiInput": "",
33
33
  "Primer::Alpha::NavList": "",
34
+ "Primer::Alpha::NavList::Divider": "",
34
35
  "Primer::Alpha::NavList::Group": "",
35
36
  "Primer::Alpha::NavList::Item": "",
36
37
  "Primer::Alpha::Navigation::Tab": "",
data/static/classes.json CHANGED
@@ -237,6 +237,9 @@
237
237
  "Subhead-actions": [
238
238
  "Primer::Beta::Subhead"
239
239
  ],
240
+ "ActionListHeader": [
241
+ "Primer::Alpha::ActionList"
242
+ ],
240
243
  "SegmentedControl": [
241
244
  "Primer::Alpha::SegmentedControl"
242
245
  ],
@@ -381,9 +381,12 @@
381
381
  "Primer::Alpha::MultiInput": {
382
382
  },
383
383
  "Primer::Alpha::NavList": {
384
+ "Divider": "Primer::Alpha::NavList::Divider",
384
385
  "Group": "Primer::Alpha::NavList::Group",
385
386
  "Item": "Primer::Alpha::NavList::Item"
386
387
  },
388
+ "Primer::Alpha::NavList::Divider": {
389
+ },
387
390
  "Primer::Alpha::NavList::Group": {
388
391
  },
389
392
  "Primer::Alpha::NavList::Item": {