primer_view_components 0.0.6 → 0.0.11

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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +71 -30
  3. data/README.md +1 -158
  4. data/app/components/primer/avatar_component.rb +11 -0
  5. data/app/components/primer/base_component.rb +7 -12
  6. data/app/components/primer/blankslate_component.html.erb +8 -2
  7. data/app/components/primer/blankslate_component.rb +70 -118
  8. data/app/components/primer/border_box_component.rb +16 -4
  9. data/app/components/primer/box_component.rb +2 -0
  10. data/app/components/primer/breadcrumb_component.rb +13 -20
  11. data/app/components/primer/button_component.rb +21 -4
  12. data/app/components/primer/component.rb +1 -0
  13. data/app/components/primer/counter_component.rb +5 -0
  14. data/app/components/primer/details_component.rb +4 -4
  15. data/app/components/primer/flash_component.html.erb +14 -0
  16. data/app/components/primer/flash_component.rb +73 -0
  17. data/app/components/primer/label_component.rb +17 -0
  18. data/app/components/primer/layout_component.rb +18 -1
  19. data/app/components/primer/link_component.rb +10 -0
  20. data/app/components/primer/octicon_component.rb +45 -0
  21. data/app/components/primer/popover_component.rb +38 -0
  22. data/app/components/primer/progress_bar_component.rb +29 -19
  23. data/app/components/primer/slot.rb +1 -0
  24. data/app/components/primer/spinner_component.html.erb +6 -0
  25. data/app/components/primer/spinner_component.rb +38 -0
  26. data/app/components/primer/state_component.rb +19 -7
  27. data/app/components/primer/subhead_component.rb +45 -20
  28. data/app/components/primer/text_component.rb +6 -0
  29. data/app/components/primer/timeline_item_component.rb +24 -0
  30. data/app/components/primer/view_components.rb +3 -0
  31. data/lib/primer/classify.rb +4 -0
  32. data/lib/primer/view_components/version.rb +1 -1
  33. metadata +27 -8
@@ -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,6 +10,17 @@ module Primer
9
10
  with_slot :footer, class_name: "Footer"
10
11
  with_slot :row, collection: true, class_name: "Row"
11
12
 
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 kwargs [Hash] <%= link_to_style_arguments_docs %>
12
24
  def initialize(**kwargs)
13
25
  @kwargs = kwargs
14
26
  @kwargs[:tag] = :div
@@ -23,8 +35,8 @@ module Primer
23
35
  end
24
36
 
25
37
  class Header < Primer::Slot
26
-
27
38
  attr_reader :kwargs
39
+ # @param kwargs [Hash] <%= link_to_style_arguments_docs %>
28
40
  def initialize(**kwargs)
29
41
  @kwargs = kwargs
30
42
  @kwargs[:tag] = :div
@@ -36,8 +48,8 @@ module Primer
36
48
  end
37
49
 
38
50
  class Body < Primer::Slot
39
-
40
51
  attr_reader :kwargs
52
+ # @param kwargs [Hash] <%= link_to_style_arguments_docs %>
41
53
  def initialize(**kwargs)
42
54
  @kwargs = kwargs
43
55
  @kwargs[:tag] = :div
@@ -49,8 +61,8 @@ module Primer
49
61
  end
50
62
 
51
63
  class Footer < Primer::Slot
52
-
53
64
  attr_reader :kwargs
65
+ # @param kwargs [Hash] <%= link_to_style_arguments_docs %>
54
66
  def initialize(**kwargs)
55
67
  @kwargs = kwargs
56
68
  @kwargs[:tag] = :div
@@ -62,8 +74,8 @@ module Primer
62
74
  end
63
75
 
64
76
  class Row < Primer::Slot
65
-
66
77
  attr_reader :kwargs
78
+ # @param kwargs [Hash] <%= link_to_style_arguments_docs %>
67
79
  def initialize(**kwargs)
68
80
  @kwargs = kwargs
69
81
  @kwargs[:tag] = :li
@@ -1,7 +1,9 @@
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
6
+ # @param kwargs [Hash] <%= link_to_style_arguments_docs %>
5
7
  def initialize(**kwargs)
6
8
  @kwargs = kwargs
7
9
  @kwargs[:tag] = :div
@@ -1,31 +1,20 @@
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
 
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 kwargs [Hash] <%= link_to_style_arguments_docs %>
29
18
  def initialize(**kwargs)
30
19
  @kwargs = kwargs
31
20
  @kwargs[:tag] = :nav
@@ -36,9 +25,13 @@ module Primer
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
30
  attr_reader :href, :kwargs
41
31
 
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 kwargs [Hash] <%= link_to_style_arguments_docs %>
42
35
  def initialize(href: nil, selected: false, **kwargs)
43
36
  @href, @kwargs = href, kwargs
44
37
 
@@ -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,6 +26,22 @@ 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,
@@ -34,19 +51,19 @@ module Primer
34
51
  **kwargs
35
52
  )
36
53
  @kwargs = kwargs
37
- @kwargs[:tag] = fetch_or_fallback(TAG_OPTIONS, tag.to_sym, DEFAULT_TAG)
54
+ @kwargs[:tag] = fetch_or_fallback(TAG_OPTIONS, tag, DEFAULT_TAG)
38
55
 
39
56
  if @kwargs[:tag] == :a
40
57
  @kwargs[:role] = :button
41
58
  else
42
- @kwargs[:type] = type.to_sym
59
+ @kwargs[:type] = type
43
60
  end
44
61
 
45
62
  @kwargs[:classes] = class_names(
46
63
  "btn",
47
64
  kwargs[:classes],
48
- BUTTON_TYPE_MAPPINGS[fetch_or_fallback(BUTTON_TYPE_OPTIONS, button_type.to_sym, DEFAULT_BUTTON_TYPE)],
49
- VARIANT_MAPPINGS[fetch_or_fallback(VARIANT_OPTIONS, variant.to_sym, DEFAULT_VARIANT)],
65
+ BUTTON_TYPE_MAPPINGS[fetch_or_fallback(BUTTON_TYPE_OPTIONS, button_type, DEFAULT_BUTTON_TYPE)],
66
+ VARIANT_MAPPINGS[fetch_or_fallback(VARIANT_OPTIONS, variant, DEFAULT_VARIANT)],
50
67
  "BtnGroup-item" => group_item
51
68
  )
52
69
  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
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
+ # Use Primer::CounterComponent to add a count to navigational elements and buttons.
4
5
  class CounterComponent < Primer::Component
5
6
  DEFAULT_SCHEME = :default
6
7
  SCHEME_MAPPINGS = {
@@ -9,6 +10,10 @@ module Primer
9
10
  :light_gray => "Counter Counter--gray-light",
10
11
  }.freeze
11
12
 
13
+ #
14
+ # @example 34|Default
15
+ # <%= render(Primer::CounterComponent.new(count: 25)) %>
16
+ #
12
17
  # @param count [Integer, Float::INFINITY, nil] The number to be displayed (e.x. # of issues, pull requests)
13
18
  # @param scheme [Symbol] Color scheme. One of `SCHEME_MAPPINGS.keys`.
14
19
  # @param limit [Integer] Maximum value to display. (e.x. if count == 6,000 and limit == 5000, counter will display "5,000+")
@@ -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)
22
+ def initialize(overlay: NO_OVERLAY, reset: false, **kwargs)
23
23
  @kwargs = kwargs
24
24
  @kwargs[:tag] = :details
25
25
  @kwargs[:classes] = class_names(
26
26
  kwargs[:classes],
27
- OVERLAY_MAPPINGS[fetch_or_fallback(OVERLAY_MAPPINGS.keys, overlay.to_sym, OVERLAY_DEFAULT)],
27
+ OVERLAY_MAPPINGS[fetch_or_fallback(OVERLAY_MAPPINGS.keys, overlay, NO_OVERLAY)],
28
28
  "details-reset" => reset
29
29
  )
30
30
  end
@@ -0,0 +1,14 @@
1
+ <%= render Primer::BaseComponent.new(**@kwargs) do %>
2
+ <%= render(Primer::OcticonComponent.new(icon: @icon)) if @icon %>
3
+ <%= content %>
4
+ <% if @dismissible %>
5
+ <button class="flash-close js-flash-close" type="button" aria-label="Close">
6
+ <%= render(Primer::OcticonComponent.new(icon: "x")) %>
7
+ </button>
8
+ <% end %>
9
+ <% if actions.present? %>
10
+ <%= render Primer::BaseComponent.new(**actions.kwargs) do %>
11
+ <%= actions.content %>
12
+ <% end %>
13
+ <% end %>
14
+ <% end %>
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ # Use the Flash component to inform users of successful or pending actions.
5
+ class FlashComponent < Primer::Component
6
+ include ViewComponent::Slotable
7
+
8
+ with_slot :actions, class_name: "Actions"
9
+
10
+ DEFAULT_VARIANT = :default
11
+ VARIANT_MAPPINGS = {
12
+ DEFAULT_VARIANT => "",
13
+ :warning => "flash-warn",
14
+ :danger => "flash-error",
15
+ :success => "flash-success"
16
+ }.freeze
17
+ # @example 280|Variants
18
+ # <%= render(Primer::FlashComponent.new) { "This is a flash message!" } %>
19
+ # <%= render(Primer::FlashComponent.new(variant: :warning)) { "This is a warning flash message!" } %>
20
+ # <%= render(Primer::FlashComponent.new(variant: :danger)) { "This is a danger flash message!" } %>
21
+ # <%= render(Primer::FlashComponent.new(variant: :success)) { "This is a success flash message!" } %>
22
+ #
23
+ # @example 80|Full width
24
+ # <%= render(Primer::FlashComponent.new(full: true)) { "This is a full width flash message!" } %>
25
+ #
26
+ # @example 80|Dismissible
27
+ # <%= render(Primer::FlashComponent.new(dismissible: true)) { "This is a dismissible flash message!" } %>
28
+ #
29
+ # @example 80|Icon
30
+ # <%= render(Primer::FlashComponent.new(icon: "people")) { "This is a flash message with an icon!" } %>
31
+ #
32
+ # @example 80|With actions
33
+ # <%= render(Primer::FlashComponent.new) do |component| %>
34
+ # This is a flash message with actions!
35
+ # <% component.slot(:actions) do %>
36
+ # <%= render(Primer::ButtonComponent.new(variant: :small)) { "Take action" } %>
37
+ # <% end %>
38
+ # <% end %>
39
+ #
40
+ # @param full [Boolean] Whether the component should take up the full width of the screen.
41
+ # @param spacious [Boolean] Whether to add margin to the bottom of the component.
42
+ # @param dismissible [Boolean] Whether the component can be dismissed with an X button.
43
+ # @param icon [String] Name of Octicon icon to use.
44
+ # @param variant [Symbol] <%= one_of(Primer::FlashComponent::VARIANT_MAPPINGS.keys) %>
45
+ # @param kwargs [Hash] <%= link_to_style_arguments_docs %>
46
+ def initialize(full: false, spacious: false, dismissible: false, icon: nil, variant: DEFAULT_VARIANT, **kwargs)
47
+ @icon = icon
48
+ @dismissible = dismissible
49
+ @kwargs = kwargs
50
+ @kwargs[:tag] = :div
51
+ @kwargs[:classes] = class_names(
52
+ @kwargs[:classes],
53
+ "flash",
54
+ VARIANT_MAPPINGS[fetch_or_fallback(VARIANT_MAPPINGS.keys, variant, DEFAULT_VARIANT)],
55
+ "flash-full": full
56
+ )
57
+ @kwargs[:mb] ||= spacious ? 4 : nil
58
+ end
59
+
60
+ class Actions < ViewComponent::Slot
61
+ include ClassNameHelper
62
+
63
+ attr_reader :kwargs
64
+
65
+ # @param kwargs [Hash] <%= link_to_style_arguments_docs %>
66
+ def initialize(**kwargs)
67
+ @kwargs = kwargs
68
+ @kwargs[:tag] = :div
69
+ @kwargs[:classes] = class_names(@kwargs[:classes], "flash-action")
70
+ end
71
+ end
72
+ end
73
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
+ # Use labels to add contextual metadata to a design.
4
5
  class LabelComponent < Primer::Component
5
6
  SCHEME_MAPPINGS = {
6
7
  # gray
@@ -28,6 +29,22 @@ module Primer
28
29
  }.freeze
29
30
  VARIANT_OPTIONS = VARIANT_MAPPINGS.keys << nil
30
31
 
32
+ # @example 40|Schemes
33
+ # <%= render(Primer::LabelComponent.new(title: "Label: Label")) { "default" } %>
34
+ # <%= render(Primer::LabelComponent.new(title: "Label: Label", scheme: :gray)) { "gray" } %>
35
+ # <%= render(Primer::LabelComponent.new(title: "Label: Label", scheme: :dark_gray)) { "dark_gray" } %>
36
+ # <%= render(Primer::LabelComponent.new(title: "Label: Label", scheme: :yellow)) { "yellow" } %>
37
+ # <%= render(Primer::LabelComponent.new(title: "Label: Label", scheme: :green)) { "green" } %>
38
+ # <%= render(Primer::LabelComponent.new(title: "Label: Label", scheme: :purple)) { "purple" } %>
39
+ #
40
+ # @example 40|Variants
41
+ # <%= render(Primer::LabelComponent.new(title: "Label: Label")) { "Default" } %>
42
+ # <%= render(Primer::LabelComponent.new(title: "Label: Label", variant: :large)) { "Large" } %>
43
+ #
44
+ # @param title [String] `title` attribute for the component element.
45
+ # @param scheme [Symbol] <%= one_of(Primer::LabelComponent::SCHEME_OPTIONS) %>
46
+ # @param variant [Symbol] <%= one_of(Primer::LabelComponent::VARIANT_OPTIONS) %>
47
+ # @param kwargs [Hash] <%= link_to_style_arguments_docs %>
31
48
  def initialize(title:, scheme: nil, variant: nil, **kwargs)
32
49
  @kwargs = kwargs
33
50
  @kwargs[:bg] = :blue if scheme.nil?
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
+ # Use Layout to build a main/sidebar layout.
4
5
  class LayoutComponent < Primer::Component
5
6
  with_content_areas :main, :sidebar
6
7
 
@@ -11,9 +12,25 @@ module Primer
11
12
  DEFAULT_SIDEBAR_COL = 3
12
13
  ALLOWED_SIDEBAR_COLS = (1..(MAX_COL - 1)).to_a.freeze
13
14
 
15
+ # @example 40|Default
16
+ # <%= render(Primer::LayoutComponent.new) do |component| %>
17
+ # <% component.with(:sidebar) { "Sidebar" } %>
18
+ # <% component.with(:main) { "Main" } %>
19
+ # <% end %>
20
+ #
21
+ # @example 40|Left sidebar
22
+ # <%= render(Primer::LayoutComponent.new(side: :left)) do |component| %>
23
+ # <% component.with(:sidebar) { "Sidebar" } %>
24
+ # <% component.with(:main) { "Main" } %>
25
+ # <% end %>
26
+ #
27
+ # @param responsive [Boolean] Whether to collapse layout to a single column at smaller widths.
28
+ # @param side [Symbol] Which side to display the sidebar on. <%= one_of(Primer::LayoutComponent::ALLOWED_SIDES) %>
29
+ # @param sidebar_col [Integer] Sidebar column width.
30
+ # @param kwargs [Hash] <%= link_to_style_arguments_docs %>
14
31
  def initialize(responsive: false, side: DEFAULT_SIDE, sidebar_col: DEFAULT_SIDEBAR_COL, **kwargs)
15
32
  @kwargs = kwargs
16
- @side = fetch_or_fallback(ALLOWED_SIDES, side.to_sym, DEFAULT_SIDE)
33
+ @side = fetch_or_fallback(ALLOWED_SIDES, side, DEFAULT_SIDE)
17
34
  @responsive = responsive
18
35
  @kwargs[:classes] = class_names(
19
36
  "gutter-condensed gutter-lg",
@@ -1,7 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
+ # Use links for moving from one page to another. The Link component styles anchor tags with default blue styling and hover text-decoration.
4
5
  class LinkComponent < Primer::Component
6
+ # @example 40|Default
7
+ # <%= render(Primer::LinkComponent.new(href: "http://www.google.com")) { "Link" } %>
8
+ #
9
+ # @example 40|Muted
10
+ # <%= render(Primer::LinkComponent.new(href: "http://www.google.com", muted: true)) { "Link" } %>
11
+ #
12
+ # @param href [String] URL to be used for the Link
13
+ # @param muted [Boolean] Uses light gray for Link color, and blue on hover
14
+ # @param kwargs [Hash] <%= link_to_style_arguments_docs %>
5
15
  def initialize(href:, muted: false, **kwargs)
6
16
  @kwargs = kwargs
7
17
  @kwargs[:tag] = :a
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ # Renders an [Octicon](https://primer.style/octicons/) with <%= link_to_style_arguments_docs %>.
5
+ class OcticonComponent < Primer::Component
6
+ include Primer::ClassNameHelper
7
+ include OcticonsHelper
8
+
9
+ SIZE_DEFAULT = :small
10
+ SIZE_MAPPINGS = {
11
+ SIZE_DEFAULT => 16,
12
+ :medium => 32,
13
+ :large => 64,
14
+ }.freeze
15
+ SIZE_OPTIONS = SIZE_MAPPINGS.keys
16
+
17
+ # @example 25|Default
18
+ # <%= render(Primer::OcticonComponent.new(icon: "check")) %>
19
+ #
20
+ # @example 40|Medium
21
+ # <%= render(Primer::OcticonComponent.new(icon: "people", size: :medium)) %>
22
+ #
23
+ # @example 80|Large
24
+ # <%= render(Primer::OcticonComponent.new(icon: "x", size: :large)) %>
25
+ #
26
+ # @param icon [String] Name of [Octicon](https://primer.style/octicons/) to use.
27
+ # @param size [Symbol] <%= one_of(Primer::OcticonComponent::SIZE_OPTIONS) %>
28
+ # @param kwargs [Hash] <%= link_to_style_arguments_docs %>
29
+ def initialize(icon:, size: SIZE_DEFAULT, **kwargs)
30
+ @icon, @kwargs = icon, kwargs
31
+
32
+ @kwargs[:class] = Primer::Classify.call(**@kwargs)[:class]
33
+ @kwargs[:height] ||= SIZE_MAPPINGS[size]
34
+
35
+ # Filter out classify options to prevent them from becoming invalid html attributes.
36
+ # Note height and width are both classify options and valid html attributes.
37
+ octicon_helper_options = @kwargs.slice(:height, :width)
38
+ @kwargs = @kwargs.except(*Primer::Classify::VALID_KEYS, :classes).merge(octicon_helper_options)
39
+ end
40
+
41
+ def call
42
+ octicon(@icon, **@kwargs)
43
+ end
44
+ end
45
+ end