primer_view_components 0.0.18 → 0.0.23

Sign up to get free protection for your applications and to get access to all the features.
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