primer_view_components 0.0.18 → 0.0.23

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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +101 -0
  3. data/app/assets/javascripts/primer_view_components.js +2 -0
  4. data/app/assets/javascripts/primer_view_components.js.map +1 -0
  5. data/app/components/primer/avatar_component.rb +27 -9
  6. data/app/components/primer/avatar_stack_component.html.erb +10 -0
  7. data/app/components/primer/avatar_stack_component.rb +81 -0
  8. data/app/components/primer/base_component.rb +4 -4
  9. data/app/components/primer/blankslate_component.html.erb +3 -3
  10. data/app/components/primer/blankslate_component.rb +16 -24
  11. data/app/components/primer/border_box_component.html.erb +4 -18
  12. data/app/components/primer/border_box_component.rb +75 -72
  13. data/app/components/primer/box_component.rb +2 -2
  14. data/app/components/primer/breadcrumb_component.rb +1 -1
  15. data/app/components/primer/button_component.rb +2 -2
  16. data/app/components/primer/button_group_component.rb +4 -1
  17. data/app/components/primer/button_marketing_component.rb +2 -2
  18. data/app/components/primer/component.rb +9 -6
  19. data/app/components/primer/counter_component.rb +5 -1
  20. data/app/components/primer/details_component.html.erb +2 -6
  21. data/app/components/primer/details_component.rb +22 -35
  22. data/app/components/primer/dropdown/menu_component.html.erb +12 -0
  23. data/app/components/primer/dropdown/menu_component.rb +48 -0
  24. data/app/components/primer/dropdown_component.html.erb +9 -0
  25. data/app/components/primer/dropdown_component.rb +75 -0
  26. data/app/components/primer/dropdown_menu_component.rb +8 -4
  27. data/app/components/primer/flash_component.html.erb +4 -7
  28. data/app/components/primer/flash_component.rb +18 -18
  29. data/app/components/primer/flex_component.rb +38 -1
  30. data/app/components/primer/flex_item_component.rb +15 -1
  31. data/app/components/primer/heading_component.rb +3 -1
  32. data/app/components/primer/label_component.rb +15 -25
  33. data/app/components/primer/layout_component.rb +2 -2
  34. data/app/components/primer/link_component.rb +6 -2
  35. data/app/components/primer/markdown_component.rb +293 -0
  36. data/app/components/primer/menu_component.html.erb +6 -0
  37. data/app/components/primer/menu_component.rb +71 -0
  38. data/app/components/primer/octicon_component.rb +9 -3
  39. data/app/components/primer/popover_component.rb +5 -5
  40. data/app/components/primer/primer.js +1 -0
  41. data/app/components/primer/primer.ts +1 -0
  42. data/app/components/primer/progress_bar_component.rb +5 -5
  43. data/app/components/primer/spinner_component.rb +7 -3
  44. data/app/components/primer/state_component.rb +21 -10
  45. data/app/components/primer/subhead_component.html.erb +3 -15
  46. data/app/components/primer/subhead_component.rb +45 -61
  47. data/app/components/primer/tab_container_component.js +1 -0
  48. data/app/components/primer/tab_container_component.rb +41 -0
  49. data/app/components/primer/tab_container_component.ts +1 -0
  50. data/app/components/primer/tab_nav_component.html.erb +17 -0
  51. data/app/components/primer/tab_nav_component.rb +108 -0
  52. data/app/components/primer/text_component.rb +1 -1
  53. data/app/components/primer/timeline_item_component.html.erb +4 -16
  54. data/app/components/primer/timeline_item_component.rb +41 -52
  55. data/app/components/primer/tooltip_component.rb +5 -5
  56. data/app/components/primer/truncate_component.rb +4 -4
  57. data/app/components/primer/underline_nav_component.rb +2 -2
  58. data/{lib → app/lib}/primer/class_name_helper.rb +0 -0
  59. data/{lib → app/lib}/primer/classify.rb +21 -10
  60. data/app/lib/primer/classify/cache.rb +125 -0
  61. data/{lib → app/lib}/primer/fetch_or_fallback_helper.rb +1 -1
  62. data/{lib → app/lib}/primer/join_style_arguments_helper.rb +1 -1
  63. data/app/lib/primer/view_helper.rb +22 -0
  64. data/app/lib/primer/view_helper/dsl.rb +34 -0
  65. data/lib/primer/view_components.rb +32 -1
  66. data/lib/primer/view_components/engine.rb +11 -3
  67. data/lib/primer/view_components/version.rb +5 -1
  68. data/lib/yard/renders_many_handler.rb +19 -0
  69. data/lib/yard/renders_one_handler.rb +19 -0
  70. data/static/statuses.json +1 -0
  71. metadata +61 -10
  72. data/app/components/primer/view_components.rb +0 -56
@@ -3,91 +3,94 @@
3
3
  module Primer
4
4
  # BorderBox is a Box component with a border.
5
5
  class BorderBoxComponent < Primer::Component
6
- include ViewComponent::Slotable
6
+ include ViewComponent::SlotableV2
7
7
 
8
- with_slot :header, class_name: "Header"
9
- with_slot :body, class_name: "Body"
10
- with_slot :footer, class_name: "Footer"
11
- with_slot :row, collection: true, class_name: "Row"
8
+ # Optional Header.
9
+ #
10
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
11
+ renders_one :header, lambda { |**system_arguments|
12
+ system_arguments[:tag] = :div
13
+ system_arguments[:classes] = class_names(
14
+ "Box-header",
15
+ system_arguments[:classes]
16
+ )
12
17
 
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 %>
18
+ Primer::BaseComponent.new(**system_arguments)
19
+ }
20
+
21
+ # Optional Body.
22
22
  #
23
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(
28
- "Box",
24
+ renders_one :body, lambda { |**system_arguments|
25
+ system_arguments[:tag] = :div
26
+ system_arguments[:classes] = class_names(
27
+ "Box-body",
29
28
  system_arguments[:classes]
30
29
  )
31
- end
32
30
 
33
- def render?
34
- rows.any? || header.present? || body.present? || footer.present?
35
- end
31
+ Primer::BaseComponent.new(**system_arguments)
32
+ }
36
33
 
37
- # :nodoc
38
- class Header < Primer::Slot
39
- attr_reader :system_arguments
40
- # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
41
- def initialize(**system_arguments)
42
- @system_arguments = system_arguments
43
- @system_arguments[:tag] = :div
44
- @system_arguments[:classes] = class_names(
45
- "Box-header",
46
- system_arguments[:classes]
47
- )
48
- end
49
- end
34
+ # Optional Footer.
35
+ #
36
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
37
+ renders_one :footer, lambda { |**system_arguments|
38
+ system_arguments[:tag] = :div
39
+ system_arguments[:classes] = class_names(
40
+ "Box-footer",
41
+ system_arguments[:classes]
42
+ )
43
+
44
+ Primer::BaseComponent.new(**system_arguments)
45
+ }
46
+
47
+ # Use Rows to add rows with borders and maintain the same padding.
48
+ #
49
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
50
+ renders_many :rows, lambda { |**system_arguments|
51
+ system_arguments[:tag] = :li
52
+ system_arguments[:classes] = class_names(
53
+ "Box-row",
54
+ system_arguments[:classes]
55
+ )
56
+
57
+ Primer::BaseComponent.new(**system_arguments)
58
+ }
50
59
 
51
- # :nodoc
52
- class Body < Primer::Slot
53
- attr_reader :system_arguments
54
- # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
55
- def initialize(**system_arguments)
56
- @system_arguments = system_arguments
57
- @system_arguments[:tag] = :div
58
- @system_arguments[:classes] = class_names(
59
- "Box-body",
60
- system_arguments[:classes]
61
- )
62
- end
60
+ # @example Header, body, rows, and footer
61
+ # <%= render(Primer::BorderBoxComponent.new) do |component| %>
62
+ # <% component.header do %>
63
+ # Header
64
+ # <% end %>
65
+ # <% component.body do %>
66
+ # Body
67
+ # <% end %>
68
+ # <% component.row do %>
69
+ # <% if true %>
70
+ # Row one
71
+ # <% end %>
72
+ # <% end %>
73
+ # <% component.row do %>
74
+ # Row two
75
+ # <% end %>
76
+ # <% component.footer do %>
77
+ # Footer
78
+ # <% end %>
79
+ # <% end %>
80
+ #
81
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
82
+ def initialize(**system_arguments)
83
+ @system_arguments = system_arguments
84
+ @system_arguments[:tag] = :div
85
+ @system_arguments[:classes] = class_names("Box", system_arguments[:classes])
63
86
  end
64
87
 
65
- # :nodoc
66
- class Footer < Primer::Slot
67
- attr_reader :system_arguments
68
- # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
69
- def initialize(**system_arguments)
70
- @system_arguments = system_arguments
71
- @system_arguments[:tag] = :div
72
- @system_arguments[:classes] = class_names(
73
- "Box-footer",
74
- system_arguments[:classes]
75
- )
76
- end
88
+ def render?
89
+ rows.any? || header.present? || body.present? || footer.present?
77
90
  end
78
91
 
79
- # :nodoc
80
- class Row < Primer::Slot
81
- attr_reader :system_arguments
82
- # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
83
- def initialize(**system_arguments)
84
- @system_arguments = system_arguments
85
- @system_arguments[:tag] = :li
86
- @system_arguments[:classes] = class_names(
87
- "Box-row",
88
- system_arguments[:classes]
89
- )
90
- end
92
+ def self.status
93
+ Primer::Component::STATUSES[:beta]
91
94
  end
92
95
  end
93
96
  end
@@ -3,10 +3,10 @@
3
3
  module Primer
4
4
  # A basic wrapper component for most layout related needs.
5
5
  class BoxComponent < Primer::Component
6
- # @example 20|Default
6
+ # @example Default
7
7
  # <%= render(Primer::BoxComponent.new) { "Your content here" } %>
8
8
  #
9
- # @example 54|Color and padding
9
+ # @example Color and padding
10
10
  # <%= render(Primer::BoxComponent.new(bg: :gray, p: 3)) { "Hello world" } %>
11
11
  #
12
12
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
@@ -7,7 +7,7 @@ module Primer
7
7
 
8
8
  with_slot :item, collection: true, class_name: "BreadcrumbItem"
9
9
 
10
- # @example 40|Basic
10
+ # @example Basic
11
11
  # <%= render(Primer::BreadcrumbComponent.new) do |component| %>
12
12
  # <% component.slot(:item, href: "/") do %>Home<% end %>
13
13
  # <% component.slot(:item, href: "/about") do %>About<% end %>
@@ -26,13 +26,13 @@ module Primer
26
26
  DEFAULT_TYPE = :button
27
27
  TYPE_OPTIONS = [DEFAULT_TYPE, :reset, :submit].freeze
28
28
 
29
- # @example 50|Button types
29
+ # @example Button types
30
30
  # <%= render(Primer::ButtonComponent.new) { "Default" } %>
31
31
  # <%= render(Primer::ButtonComponent.new(button_type: :primary)) { "Primary" } %>
32
32
  # <%= render(Primer::ButtonComponent.new(button_type: :danger)) { "Danger" } %>
33
33
  # <%= render(Primer::ButtonComponent.new(button_type: :outline)) { "Outline" } %>
34
34
  #
35
- # @example 50|Variants
35
+ # @example Variants
36
36
  # <%= render(Primer::ButtonComponent.new(variant: :small)) { "Small" } %>
37
37
  # <%= render(Primer::ButtonComponent.new(variant: :medium)) { "Medium" } %>
38
38
  # <%= render(Primer::ButtonComponent.new(variant: :large)) { "Large" } %>
@@ -5,9 +5,12 @@ module Primer
5
5
  class ButtonGroupComponent < Primer::Component
6
6
  include ViewComponent::SlotableV2
7
7
 
8
+ # Required list of buttons to be rendered.
9
+ #
10
+ # @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::ButtonComponent) %>.
8
11
  renders_many :buttons, ->(**kwargs) { Primer::ButtonComponent.new(group_item: true, **kwargs) }
9
12
 
10
- # @example 50|Default
13
+ # @example Default
11
14
  # <%= render(Primer::ButtonGroupComponent.new) do |component|
12
15
  # component.button { "Default" }
13
16
  # component.button(button_type: :primary) { "Primary" }
@@ -25,7 +25,7 @@ module Primer
25
25
  DEFAULT_TYPE = :button
26
26
  TYPE_OPTIONS = [DEFAULT_TYPE, :submit].freeze
27
27
 
28
- # @example 125|Button types
28
+ # @example Button types
29
29
  # <%= render(Primer::ButtonMarketingComponent.new(mr: 2)) { "Default" } %>
30
30
  # <%= render(Primer::ButtonMarketingComponent.new(button_type: :primary, mr: 2)) { "Primary" } %>
31
31
  # <%= render(Primer::ButtonMarketingComponent.new(button_type: :outline)) { "Outline" } %>
@@ -33,7 +33,7 @@ module Primer
33
33
  # <%= render(Primer::ButtonMarketingComponent.new(button_type: :transparent)) { "Transparent" } %>
34
34
  # </div>
35
35
  #
36
- # @example 75|Sizes
36
+ # @example Sizes
37
37
  # <%= render(Primer::ButtonMarketingComponent.new(mr: 2)) { "Default" } %>
38
38
  # <%= render(Primer::ButtonMarketingComponent.new(variant: :large)) { "Large" } %>
39
39
  #
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "octicons_helper/helper"
4
+
3
5
  module Primer
4
6
  # @private
5
7
  class Component < ViewComponent::Base
@@ -7,18 +9,19 @@ module Primer
7
9
  include FetchOrFallbackHelper
8
10
  include OcticonsHelper
9
11
  include JoinStyleArgumentsHelper
12
+ include ViewHelper::DSL
13
+ include ViewHelper
10
14
 
11
15
  # sourced from https://primer.style/doctocat/usage/front-matter#status
12
16
  STATUSES = {
13
- deprecated: :deprecated,
14
- review: :review,
15
- experimental: :experimental,
16
- new: :new,
17
- stable: :stable
17
+ alpha: :alpha,
18
+ beta: :beta,
19
+ stable: :stable,
20
+ deprecated: :deprecated
18
21
  }.freeze
19
22
 
20
23
  def self.status
21
- STATUSES[:experimental]
24
+ STATUSES[:alpha]
22
25
  end
23
26
  end
24
27
  end
@@ -11,7 +11,7 @@ module Primer
11
11
  }.freeze
12
12
 
13
13
  #
14
- # @example 34|Default
14
+ # @example Default
15
15
  # <%= render(Primer::CounterComponent.new(count: 25)) %>
16
16
  #
17
17
  # @param count [Integer, Float::INFINITY, nil] The number to be displayed (e.x. # of issues, pull requests)
@@ -51,6 +51,10 @@ module Primer
51
51
  render(Primer::BaseComponent.new(**@system_arguments)) { value }
52
52
  end
53
53
 
54
+ def self.status
55
+ Primer::Component::STATUSES[:beta]
56
+ end
57
+
54
58
  private
55
59
 
56
60
  def title
@@ -1,8 +1,4 @@
1
1
  <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
- <%= render summary.component do %>
3
- <%= summary.content %>
4
- <% end %>
5
- <%= render body.component do %>
6
- <%= body.content %>
7
- <% end %>
2
+ <%= summary %>
3
+ <%= body %>
8
4
  <% end %>
@@ -3,7 +3,7 @@
3
3
  module Primer
4
4
  # Use DetailsComponent to reveal content after clicking a button.
5
5
  class DetailsComponent < Primer::Component
6
- include ViewComponent::Slotable
6
+ include ViewComponent::SlotableV2
7
7
 
8
8
  NO_OVERLAY = :none
9
9
  OVERLAY_MAPPINGS = {
@@ -12,8 +12,27 @@ module Primer
12
12
  :dark => "details-overlay details-overlay-dark"
13
13
  }.freeze
14
14
 
15
- with_slot :body, class_name: "Body"
16
- with_slot :summary, class_name: "Summary"
15
+ # Use the Summary slot as a trigger to reveal the content.
16
+ #
17
+ # @param button [Boolean] Whether to render the Summary as a button or not.
18
+ # @param kwargs [Hash] The same arguments as <%= link_to_system_arguments_docs %>.
19
+ renders_one :summary, lambda { |button = true, **system_arguments|
20
+ system_arguments = system_arguments
21
+ system_arguments[:tag] = :summary
22
+ system_arguments[:role] = "button"
23
+
24
+ Primer::BaseComponent.new(**system_arguments) unless button
25
+
26
+ Primer::ButtonComponent.new(**system_arguments)
27
+ }
28
+
29
+ # Use the Body slot as the main content to be shown when triggered by the Summary.
30
+ #
31
+ # @param kwargs [Hash] The same arguments as <%= link_to_system_arguments_docs %>.
32
+ renders_one :body, lambda { |**system_arguments|
33
+ system_arguments[:tag] ||= :div
34
+ Primer::BaseComponent.new(**system_arguments)
35
+ }
17
36
 
18
37
  # @param overlay [Symbol] Dictates the type of overlay to render with. <%= one_of(Primer::DetailsComponent::OVERLAY_MAPPINGS.keys) %>
19
38
  # @param reset [Boolean] Defatuls to false. If set to true, it will remove the default caret and remove style from the summary element
@@ -31,37 +50,5 @@ module Primer
31
50
  def render?
32
51
  summary.present? && body.present?
33
52
  end
34
-
35
- # Use the Summary slot as a trigger to reveal the content.
36
- class Summary < Primer::Slot
37
- # @param button [Boolean] Whether to render the Summary as a button or not.
38
- # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
39
- def initialize(button: true, **system_arguments)
40
- @button = button
41
-
42
- @system_arguments = system_arguments
43
- @system_arguments[:tag] = :summary
44
- @system_arguments[:role] = "button"
45
- end
46
-
47
- def component
48
- return Primer::BaseComponent.new(**@system_arguments) unless @button
49
-
50
- Primer::ButtonComponent.new(**@system_arguments)
51
- end
52
- end
53
-
54
- # Use the Body slot as the main content to be shown when triggered by the Summary.
55
- class Body < Primer::Slot
56
- # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
57
- def initialize(**system_arguments)
58
- @system_arguments = system_arguments
59
- @system_arguments[:tag] ||= :div
60
- end
61
-
62
- def component
63
- Primer::BaseComponent.new(**@system_arguments)
64
- end
65
- end
66
53
  end
67
54
  end
@@ -0,0 +1,12 @@
1
+ <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
+ <% if @header.present? %>
3
+ <div class="dropdown-header">
4
+ <%= @header %>
5
+ </div>
6
+ <% end %>
7
+ <ul>
8
+ <% items.each do |item| %>
9
+ <%= item %>
10
+ <% end %>
11
+ </ul>
12
+ <% end %>
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Dropdown
5
+ # This component is part of `Primer::DropdownComponent` and should not be
6
+ # used as a standalone component.
7
+ class MenuComponent < Primer::Component
8
+ include ViewComponent::SlotableV2
9
+
10
+ SCHEME_DEFAULT = :default
11
+ SCHEME_MAPPINGS = {
12
+ SCHEME_DEFAULT => "",
13
+ :dark => "dropdown-menu-dark"
14
+ }.freeze
15
+
16
+ DIRECTION_DEFAULT = :se
17
+ DIRECTION_OPTIONS = [DIRECTION_DEFAULT, :sw, :w, :e, :ne, :s].freeze
18
+
19
+ renders_many :items, lambda { |divider: false, **system_arguments|
20
+ system_arguments[:tag] = :li
21
+ system_arguments[:role] = :none if divider
22
+ system_arguments[:classes] = class_names(
23
+ system_arguments[:classes],
24
+ "dropdown-item" => !divider,
25
+ "dropdown-divider" => divider
26
+ )
27
+
28
+ Primer::BaseComponent.new(**system_arguments)
29
+ }
30
+
31
+ def initialize(direction: DIRECTION_DEFAULT, scheme: SCHEME_DEFAULT, header: nil, **system_arguments)
32
+ @header = header
33
+ @direction = direction
34
+ @system_arguments = system_arguments
35
+
36
+ @system_arguments[:tag] = "details-menu"
37
+ @system_arguments[:role] = "menu"
38
+
39
+ @system_arguments[:classes] = class_names(
40
+ @system_arguments[:classes],
41
+ "dropdown-menu",
42
+ "dropdown-menu-#{fetch_or_fallback(DIRECTION_OPTIONS, direction, DIRECTION_DEFAULT)}",
43
+ SCHEME_MAPPINGS[fetch_or_fallback(SCHEME_MAPPINGS.keys, scheme, SCHEME_DEFAULT)]
44
+ )
45
+ end
46
+ end
47
+ end
48
+ end