primer_view_components 0.0.10 → 0.0.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +35 -1
  3. data/README.md +2 -175
  4. data/app/components/primer/avatar_component.rb +11 -11
  5. data/app/components/primer/base_component.rb +101 -9
  6. data/app/components/primer/blankslate_component.html.erb +1 -1
  7. data/app/components/primer/blankslate_component.rb +6 -6
  8. data/app/components/primer/border_box_component.html.erb +5 -5
  9. data/app/components/primer/border_box_component.rb +45 -33
  10. data/app/components/primer/box_component.rb +6 -4
  11. data/app/components/primer/breadcrumb_component.html.erb +2 -2
  12. data/app/components/primer/breadcrumb_component.rb +23 -30
  13. data/app/components/primer/button_component.rb +26 -9
  14. data/app/components/primer/component.rb +1 -0
  15. data/app/components/primer/counter_component.rb +16 -15
  16. data/app/components/primer/details_component.html.erb +1 -1
  17. data/app/components/primer/details_component.rb +18 -18
  18. data/app/components/primer/dropdown_menu_component.html.erb +1 -1
  19. data/app/components/primer/dropdown_menu_component.rb +6 -6
  20. data/app/components/primer/flash_component.html.erb +2 -2
  21. data/app/components/primer/flash_component.rb +42 -12
  22. data/app/components/primer/flex_component.rb +5 -5
  23. data/app/components/primer/flex_item_component.rb +5 -5
  24. data/app/components/primer/heading_component.rb +4 -4
  25. data/app/components/primer/label_component.rb +37 -14
  26. data/app/components/primer/layout_component.html.erb +1 -1
  27. data/app/components/primer/layout_component.rb +22 -5
  28. data/app/components/primer/link_component.rb +17 -7
  29. data/app/components/primer/octicon_component.rb +20 -7
  30. data/app/components/primer/popover_component.html.erb +1 -1
  31. data/app/components/primer/popover_component.rb +61 -23
  32. data/app/components/primer/progress_bar_component.html.erb +2 -2
  33. data/app/components/primer/progress_bar_component.rb +40 -30
  34. data/app/components/primer/slot.rb +1 -0
  35. data/app/components/primer/spinner_component.html.erb +1 -1
  36. data/app/components/primer/spinner_component.rb +12 -11
  37. data/app/components/primer/state_component.rb +26 -14
  38. data/app/components/primer/subhead_component.html.erb +4 -4
  39. data/app/components/primer/subhead_component.rb +68 -43
  40. data/app/components/primer/text_component.rb +10 -4
  41. data/app/components/primer/timeline_item_component.html.erb +4 -4
  42. data/app/components/primer/timeline_item_component.rb +48 -24
  43. data/app/components/primer/underline_nav_component.html.erb +1 -1
  44. data/app/components/primer/underline_nav_component.rb +5 -5
  45. data/lib/primer/classify.rb +7 -6
  46. data/lib/primer/view_components/version.rb +1 -1
  47. metadata +3 -3
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
+ # BorderBox is a Box component with a border.
4
5
  class BorderBoxComponent < Primer::Component
5
6
  include ViewComponent::Slotable
6
7
 
@@ -9,12 +10,23 @@ module Primer
9
10
  with_slot :footer, class_name: "Footer"
10
11
  with_slot :row, collection: true, class_name: "Row"
11
12
 
12
- def initialize(**kwargs)
13
- @kwargs = kwargs
14
- @kwargs[:tag] = :div
15
- @kwargs[:classes] = class_names(
13
+ # @example 350|Header, body, rows, and footer
14
+ # <%= render(Primer::BorderBoxComponent.new) do |component|
15
+ # component.slot(:header) { "Header" }
16
+ # component.slot(:body) { "Body" }
17
+ # component.slot(:row) { "Row one" }
18
+ # component.slot(:row) { "Row two" }
19
+ # component.slot(:row) { "Row three" }
20
+ # component.slot(:footer) { "Footer" }
21
+ # end %>
22
+ #
23
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
24
+ def initialize(**system_arguments)
25
+ @system_arguments = system_arguments
26
+ @system_arguments[:tag] = :div
27
+ @system_arguments[:classes] = class_names(
16
28
  "Box",
17
- kwargs[:classes]
29
+ system_arguments[:classes]
18
30
  )
19
31
  end
20
32
 
@@ -23,53 +35,53 @@ module Primer
23
35
  end
24
36
 
25
37
  class Header < Primer::Slot
26
-
27
- attr_reader :kwargs
28
- def initialize(**kwargs)
29
- @kwargs = kwargs
30
- @kwargs[:tag] = :div
31
- @kwargs[:classes] = class_names(
38
+ attr_reader :system_arguments
39
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
40
+ def initialize(**system_arguments)
41
+ @system_arguments = system_arguments
42
+ @system_arguments[:tag] = :div
43
+ @system_arguments[:classes] = class_names(
32
44
  "Box-header",
33
- kwargs[:classes]
45
+ system_arguments[:classes]
34
46
  )
35
47
  end
36
48
  end
37
49
 
38
50
  class Body < Primer::Slot
39
-
40
- attr_reader :kwargs
41
- def initialize(**kwargs)
42
- @kwargs = kwargs
43
- @kwargs[:tag] = :div
44
- @kwargs[:classes] = class_names(
51
+ attr_reader :system_arguments
52
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
53
+ def initialize(**system_arguments)
54
+ @system_arguments = system_arguments
55
+ @system_arguments[:tag] = :div
56
+ @system_arguments[:classes] = class_names(
45
57
  "Box-body",
46
- kwargs[:classes]
58
+ system_arguments[:classes]
47
59
  )
48
60
  end
49
61
  end
50
62
 
51
63
  class Footer < Primer::Slot
52
-
53
- attr_reader :kwargs
54
- def initialize(**kwargs)
55
- @kwargs = kwargs
56
- @kwargs[:tag] = :div
57
- @kwargs[:classes] = class_names(
64
+ attr_reader :system_arguments
65
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
66
+ def initialize(**system_arguments)
67
+ @system_arguments = system_arguments
68
+ @system_arguments[:tag] = :div
69
+ @system_arguments[:classes] = class_names(
58
70
  "Box-footer",
59
- kwargs[:classes]
71
+ system_arguments[:classes]
60
72
  )
61
73
  end
62
74
  end
63
75
 
64
76
  class Row < Primer::Slot
65
-
66
- attr_reader :kwargs
67
- def initialize(**kwargs)
68
- @kwargs = kwargs
69
- @kwargs[:tag] = :li
70
- @kwargs[:classes] = class_names(
77
+ attr_reader :system_arguments
78
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
79
+ def initialize(**system_arguments)
80
+ @system_arguments = system_arguments
81
+ @system_arguments[:tag] = :li
82
+ @system_arguments[:classes] = class_names(
71
83
  "Box-row",
72
- kwargs[:classes]
84
+ system_arguments[:classes]
73
85
  )
74
86
  end
75
87
  end
@@ -1,14 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
+ # A basic wrapper component for most layout related needs.
4
5
  class BoxComponent < Primer::Component
5
- def initialize(**kwargs)
6
- @kwargs = kwargs
7
- @kwargs[:tag] = :div
6
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
7
+ def initialize(**system_arguments)
8
+ @system_arguments = system_arguments
9
+ @system_arguments[:tag] = :div
8
10
  end
9
11
 
10
12
  def call
11
- render(Primer::BaseComponent.new(**@kwargs)) { content }
13
+ render(Primer::BaseComponent.new(**@system_arguments)) { content }
12
14
  end
13
15
  end
14
16
  end
@@ -1,8 +1,8 @@
1
- <%= render Primer::BaseComponent.new(**@kwargs) do %>
1
+ <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
2
  <ol>
3
3
  <% items.each do |item| %>
4
4
  <%# The <li> and <a> need to be on the same line to prevent unwanted whitespace %>
5
- <%= render Primer::BaseComponent.new(**item.kwargs) do %><%- if item.href.present? %><a href="<%= item.href %>"><%= item.content %></a><%- else %><%= item.content %><%- end %><%- end %>
5
+ <%= render Primer::BaseComponent.new(**item.system_arguments) do %><%- if item.href.present? %><a href="<%= item.href %>"><%= item.content %></a><%- else %><%= item.content %><%- end %><%- end %>
6
6
  <% end %>
7
7
  </ol>
8
8
  <% end %>
@@ -1,51 +1,44 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- ##
4
- # Breadcrumbs are used to display page hierarchy within a section of the site. All of the items in the breadcrumb "trail" are links except for the final item which is a plain string indicating the current page.
5
- #
6
- # ## Example
7
- #
8
- # The `Primer::BreadcrumbComponent` uses the [Slots API](https://github.com/github/view_component#slots-experimental) and at least one slot is required for the component to render. Each slot can accept the following parameters:
9
- #
10
- # 1. `href` (string). The URL to link to.
11
- # 2. `selected` (boolean, default=false). Flag indicating whether or not the item is selected and not rendered as a link.
12
- #
13
- # Note that if if both `href` and `selected: true` are passed in, `href` will be ignored and the item will not be rendered as a link.
14
- #
15
- # ```ruby
16
- # <%= render(Primer::BreadcrumbComponent.new) do |component| %>
17
- # <% component.slot(:item, href: "/") do %>Home<% end %>
18
- # <% component.slot(:item, href: "/about") do %>About<% end %>
19
- # <% component.slot(:item, selected: true) do %>Team<% end %>
20
- # <% end %>
21
- # ```
22
- ##
23
3
  module Primer
4
+ # Use breadcrumbs to display page hierarchy within a section of the site. All of the items in the breadcrumb "trail" are links except for the final item, which is a plain string indicating the current page.
24
5
  class BreadcrumbComponent < Primer::Component
25
6
  include ViewComponent::Slotable
26
7
 
27
8
  with_slot :item, collection: true, class_name: "BreadcrumbItem"
28
9
 
29
- def initialize(**kwargs)
30
- @kwargs = kwargs
31
- @kwargs[:tag] = :nav
32
- @kwargs[:aria] = { label: "Breadcrumb" }
10
+ # @example 40|Basic
11
+ # <%= render(Primer::BreadcrumbComponent.new) do |component| %>
12
+ # <% component.slot(:item, href: "/") do %>Home<% end %>
13
+ # <% component.slot(:item, href: "/about") do %>About<% end %>
14
+ # <% component.slot(:item, selected: true) do %>Team<% end %>
15
+ # <% end %>
16
+ #
17
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
18
+ def initialize(**system_arguments)
19
+ @system_arguments = system_arguments
20
+ @system_arguments[:tag] = :nav
21
+ @system_arguments[:aria] = { label: "Breadcrumb" }
33
22
  end
34
23
 
35
24
  def render?
36
25
  items.any?
37
26
  end
38
27
 
28
+ # _Note: if both `href` and `selected: true` are passed in, `href` will be ignored and the item will not be rendered as a link._
39
29
  class BreadcrumbItem < Primer::Slot
40
- attr_reader :href, :kwargs
30
+ attr_reader :href, :system_arguments
41
31
 
42
- def initialize(href: nil, selected: false, **kwargs)
43
- @href, @kwargs = href, kwargs
32
+ # @param href [String] The URL to link to.
33
+ # @param selected [Boolean] Whether or not the item is selected and not rendered as a link.
34
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
35
+ def initialize(href: nil, selected: false, **system_arguments)
36
+ @href, @system_arguments = href, system_arguments
44
37
 
45
38
  @href = nil if selected
46
- @kwargs[:tag] = :li
47
- @kwargs[:"aria-current"] = "page" if selected
48
- @kwargs[:classes] = "breadcrumb-item #{@kwargs[:classes]}"
39
+ @system_arguments[:tag] = :li
40
+ @system_arguments[:"aria-current"] = "page" if selected
41
+ @system_arguments[:classes] = "breadcrumb-item #{@system_arguments[:classes]}"
49
42
  end
50
43
  end
51
44
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
+ # Use buttons for actions (e.g. in forms). Use links for destinations, or moving from one page to another.
4
5
  class ButtonComponent < Primer::Component
5
6
  DEFAULT_BUTTON_TYPE = :default
6
7
  BUTTON_TYPE_MAPPINGS = {
@@ -25,26 +26,42 @@ module Primer
25
26
  DEFAULT_TYPE = :button
26
27
  TYPE_OPTIONS = [DEFAULT_TYPE, :reset, :submit].freeze
27
28
 
29
+ # @example 50|Button types
30
+ # <%= render(Primer::ButtonComponent.new) { "Default" } %>
31
+ # <%= render(Primer::ButtonComponent.new(button_type: :primary)) { "Primary" } %>
32
+ # <%= render(Primer::ButtonComponent.new(button_type: :danger)) { "Danger" } %>
33
+ # <%= render(Primer::ButtonComponent.new(button_type: :outline)) { "Outline" } %>
34
+ #
35
+ # @example 50|Variants
36
+ # <%= render(Primer::ButtonComponent.new(variant: :small)) { "Small" } %>
37
+ # <%= render(Primer::ButtonComponent.new(variant: :medium)) { "Medium" } %>
38
+ # <%= render(Primer::ButtonComponent.new(variant: :large)) { "Large" } %>
39
+ #
40
+ # @param button_type [Symbol] <%= one_of(Primer::ButtonComponent::BUTTON_TYPE_OPTIONS) %>
41
+ # @param variant [Symbol] <%= one_of(Primer::ButtonComponent::VARIANT_OPTIONS) %>
42
+ # @param tag [Symbol] <%= one_of(Primer::ButtonComponent::TAG_OPTIONS) %>
43
+ # @param type [Symbol] <%= one_of(Primer::ButtonComponent::TYPE_OPTIONS) %>
44
+ # @param group_item [Boolean] Whether button is part of a ButtonGroup.
28
45
  def initialize(
29
46
  button_type: DEFAULT_BUTTON_TYPE,
30
47
  variant: DEFAULT_VARIANT,
31
48
  tag: DEFAULT_TAG,
32
49
  type: DEFAULT_TYPE,
33
50
  group_item: false,
34
- **kwargs
51
+ **system_arguments
35
52
  )
36
- @kwargs = kwargs
37
- @kwargs[:tag] = fetch_or_fallback(TAG_OPTIONS, tag, DEFAULT_TAG)
53
+ @system_arguments = system_arguments
54
+ @system_arguments[:tag] = fetch_or_fallback(TAG_OPTIONS, tag, DEFAULT_TAG)
38
55
 
39
- if @kwargs[:tag] == :a
40
- @kwargs[:role] = :button
56
+ if @system_arguments[:tag] == :a
57
+ @system_arguments[:role] = :button
41
58
  else
42
- @kwargs[:type] = type
59
+ @system_arguments[:type] = type
43
60
  end
44
61
 
45
- @kwargs[:classes] = class_names(
62
+ @system_arguments[:classes] = class_names(
46
63
  "btn",
47
- kwargs[:classes],
64
+ system_arguments[:classes],
48
65
  BUTTON_TYPE_MAPPINGS[fetch_or_fallback(BUTTON_TYPE_OPTIONS, button_type, DEFAULT_BUTTON_TYPE)],
49
66
  VARIANT_MAPPINGS[fetch_or_fallback(VARIANT_OPTIONS, variant, DEFAULT_VARIANT)],
50
67
  "BtnGroup-item" => group_item
@@ -52,7 +69,7 @@ module Primer
52
69
  end
53
70
 
54
71
  def call
55
- render(Primer::BaseComponent.new(**@kwargs)) { content }
72
+ render(Primer::BaseComponent.new(**@system_arguments)) { content }
56
73
  end
57
74
  end
58
75
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
+ # @private
4
5
  class Component < ViewComponent::Base
5
6
  include ClassNameHelper
6
7
  include FetchOrFallbackHelper
@@ -16,11 +16,11 @@ module Primer
16
16
  #
17
17
  # @param count [Integer, Float::INFINITY, nil] The number to be displayed (e.x. # of issues, pull requests)
18
18
  # @param scheme [Symbol] Color scheme. One of `SCHEME_MAPPINGS.keys`.
19
- # @param limit [Integer] Maximum value to display. (e.x. if count == 6,000 and limit == 5000, counter will display "5,000+")
19
+ # @param limit [Integer, nil] Maximum value to display. Pass `nil` for no limit. (e.x. if `count` == 6,000 and `limit` == 5000, counter will display "5,000+")
20
20
  # @param hide_if_zero [Boolean] If true, a `hidden` attribute is added to the counter if `count` is zero.
21
21
  # @param text [String] Text to display instead of count.
22
22
  # @param round [Boolean] Whether to apply our standard rounding logic to value.
23
- # @param kwargs [Hash] Style arguments to be passed to Primer::Classify
23
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
24
24
  def initialize(
25
25
  count: 0,
26
26
  scheme: DEFAULT_SCHEME,
@@ -28,23 +28,24 @@ module Primer
28
28
  hide_if_zero: false,
29
29
  text: "",
30
30
  round: false,
31
- **kwargs
31
+ **system_arguments
32
32
  )
33
- @count, @limit, @hide_if_zero, @text, @round, @kwargs = count, limit, hide_if_zero, text, round, kwargs
33
+ @count, @limit, @hide_if_zero, @text, @round, @system_arguments = count, limit, hide_if_zero, text, round, system_arguments
34
34
 
35
- @kwargs[:title] = title
36
- @kwargs[:tag] = :span
37
- @kwargs[:classes] = class_names(
38
- @kwargs[:classes],
35
+ @has_limit = !@limit.nil?
36
+ @system_arguments[:title] = title
37
+ @system_arguments[:tag] = :span
38
+ @system_arguments[:classes] = class_names(
39
+ @system_arguments[:classes],
39
40
  SCHEME_MAPPINGS[fetch_or_fallback(SCHEME_MAPPINGS.keys, scheme, DEFAULT_SCHEME)]
40
41
  )
41
42
  if count == 0 && hide_if_zero
42
- @kwargs[:hidden] = true
43
+ @system_arguments[:hidden] = true
43
44
  end
44
45
  end
45
46
 
46
47
  def call
47
- render(Primer::BaseComponent.new(**@kwargs)) { value }
48
+ render(Primer::BaseComponent.new(**@system_arguments)) { value }
48
49
  end
49
50
 
50
51
  private
@@ -58,8 +59,8 @@ module Primer
58
59
  "Infinity"
59
60
  else
60
61
  count = @count.to_i
61
- str = number_with_delimiter([count, @limit].min)
62
- str += "+" if count > @limit
62
+ str = number_with_delimiter(@has_limit ? [count, @limit].min : count)
63
+ str += "+" if (@has_limit && count > @limit)
63
64
  str
64
65
  end
65
66
  end
@@ -73,16 +74,16 @@ module Primer
73
74
  "∞"
74
75
  else
75
76
  if @round
76
- count = [@count.to_i, @limit].min
77
+ count = @has_limit ? [@count.to_i, @limit].min : @count.to_i
77
78
  precision = count.between?(100_000, 999_999) ? 0 : 1
78
79
  units = {thousand: "k", million: "m", billion: "b"}
79
80
  str = number_to_human(count, precision: precision, significant: false, units: units, format: "%n%u")
80
81
  else
81
82
  @count = @count.to_i
82
- str = number_with_delimiter([@count, @limit].min)
83
+ str = number_with_delimiter(@has_limit ? [@count, @limit].min : @count)
83
84
  end
84
85
 
85
- str += "+" if @count.to_i > @limit
86
+ str += "+" if (@has_limit && @count.to_i > @limit)
86
87
  str
87
88
  end
88
89
  end
@@ -1,4 +1,4 @@
1
- <%= render Primer::BaseComponent.new(**@kwargs) do %>
1
+ <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
2
  <%= render summary.component do %>
3
3
  <%= summary.content %>
4
4
  <% end %>
@@ -9,9 +9,9 @@ module Primer
9
9
  class DetailsComponent < Primer::Component
10
10
  include ViewComponent::Slotable
11
11
 
12
- OVERLAY_DEFAULT = :none
12
+ NO_OVERLAY = :none
13
13
  OVERLAY_MAPPINGS = {
14
- OVERLAY_DEFAULT => "",
14
+ NO_OVERLAY => "",
15
15
  :default => "details-overlay",
16
16
  :dark => "details-overlay details-overlay-dark",
17
17
  }.freeze
@@ -19,12 +19,12 @@ module Primer
19
19
  with_slot :body, class_name: "Body"
20
20
  with_slot :summary, class_name: "Summary"
21
21
 
22
- def initialize(overlay: OVERLAY_DEFAULT, reset: false, **kwargs)
23
- @kwargs = kwargs
24
- @kwargs[:tag] = :details
25
- @kwargs[:classes] = class_names(
26
- kwargs[:classes],
27
- OVERLAY_MAPPINGS[fetch_or_fallback(OVERLAY_MAPPINGS.keys, overlay, OVERLAY_DEFAULT)],
22
+ def initialize(overlay: NO_OVERLAY, reset: false, **system_arguments)
23
+ @system_arguments = system_arguments
24
+ @system_arguments[:tag] = :details
25
+ @system_arguments[:classes] = class_names(
26
+ system_arguments[:classes],
27
+ OVERLAY_MAPPINGS[fetch_or_fallback(OVERLAY_MAPPINGS.keys, overlay, NO_OVERLAY)],
28
28
  "details-reset" => reset
29
29
  )
30
30
  end
@@ -34,29 +34,29 @@ module Primer
34
34
  end
35
35
 
36
36
  class Summary < Primer::Slot
37
- def initialize(button: true, **kwargs)
37
+ def initialize(button: true, **system_arguments)
38
38
  @button = button
39
39
 
40
- @kwargs = kwargs
41
- @kwargs[:tag] = :summary
42
- @kwargs[:role] = "button"
40
+ @system_arguments = system_arguments
41
+ @system_arguments[:tag] = :summary
42
+ @system_arguments[:role] = "button"
43
43
  end
44
44
 
45
45
  def component
46
- return Primer::BaseComponent.new(**@kwargs) unless @button
46
+ return Primer::BaseComponent.new(**@system_arguments) unless @button
47
47
 
48
- Primer::ButtonComponent.new(**@kwargs)
48
+ Primer::ButtonComponent.new(**@system_arguments)
49
49
  end
50
50
  end
51
51
 
52
52
  class Body < Primer::Slot
53
- def initialize(**kwargs)
54
- @kwargs = kwargs
55
- @kwargs[:tag] ||= :div
53
+ def initialize(**system_arguments)
54
+ @system_arguments = system_arguments
55
+ @system_arguments[:tag] ||= :div
56
56
  end
57
57
 
58
58
  def component
59
- Primer::BaseComponent.new(**@kwargs)
59
+ Primer::BaseComponent.new(**@system_arguments)
60
60
  end
61
61
  end
62
62
  end