primer_view_components 0.0.24 → 0.0.29

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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +96 -2
  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/javascripts/primer_view_components.js.map.orig +5 -0
  6. data/app/assets/javascripts/primer_view_components.js.orig +6 -0
  7. data/app/components/primer/auto_complete_component.d.ts +1 -0
  8. data/app/components/primer/auto_complete_component.html.erb +5 -0
  9. data/app/components/primer/auto_complete_component.js +1 -0
  10. data/app/components/primer/auto_complete_component.rb +98 -0
  11. data/app/components/primer/auto_complete_component.ts +1 -0
  12. data/app/components/primer/auto_complete_item_component.rb +40 -0
  13. data/app/components/primer/avatar_component.rb +8 -9
  14. data/app/components/primer/base_component.rb +7 -15
  15. data/app/components/primer/blankslate_component.html.erb +1 -5
  16. data/app/components/primer/blankslate_component.rb +2 -0
  17. data/app/components/primer/border_box_component.rb +32 -6
  18. data/app/components/primer/box_component.rb +3 -5
  19. data/app/components/primer/breadcrumb_component.rb +1 -0
  20. data/app/components/primer/component.rb +1 -13
  21. data/app/components/primer/counter_component.rb +17 -9
  22. data/app/components/primer/details_component.rb +3 -3
  23. data/app/components/primer/dropdown_menu_component.rb +2 -4
  24. data/app/components/primer/flash_component.html.erb +2 -2
  25. data/app/components/primer/flash_component.rb +2 -4
  26. data/app/components/primer/flex_component.rb +16 -16
  27. data/app/components/primer/heading_component.rb +1 -1
  28. data/app/components/primer/label_component.rb +9 -9
  29. data/app/components/primer/layout_component.html.erb +3 -9
  30. data/app/components/primer/layout_component.rb +30 -5
  31. data/app/components/primer/link_component.rb +37 -9
  32. data/app/components/primer/octicon_component.rb +4 -7
  33. data/app/components/primer/popover_component.html.erb +3 -7
  34. data/app/components/primer/popover_component.rb +58 -62
  35. data/app/components/primer/primer.d.ts +3 -0
  36. data/app/components/primer/primer.js +2 -0
  37. data/app/components/primer/primer.ts +2 -0
  38. data/app/components/primer/progress_bar_component.rb +6 -5
  39. data/app/components/primer/spinner_component.rb +2 -4
  40. data/app/components/primer/state_component.rb +2 -4
  41. data/app/components/primer/subhead_component.rb +2 -0
  42. data/app/components/primer/tab_container_component.d.ts +1 -0
  43. data/app/components/primer/text_component.rb +3 -1
  44. data/app/components/primer/time_ago_component.d.ts +1 -0
  45. data/app/components/primer/time_ago_component.js +1 -0
  46. data/app/components/primer/time_ago_component.rb +47 -0
  47. data/app/components/primer/time_ago_component.ts +1 -0
  48. data/app/components/primer/timeline_item_component.rb +2 -1
  49. data/app/components/primer/underline_nav_component.html.erb +5 -5
  50. data/app/components/primer/underline_nav_component.rb +24 -5
  51. data/app/lib/primer/classify.rb +13 -16
  52. data/app/lib/primer/classify/cache.rb +8 -3
  53. data/app/lib/primer/classify/functional_background_colors.rb +61 -0
  54. data/app/lib/primer/classify/functional_border_colors.rb +51 -0
  55. data/app/lib/primer/classify/functional_colors.rb +66 -0
  56. data/app/lib/primer/classify/functional_text_colors.rb +62 -0
  57. data/app/lib/primer/fetch_or_fallback_helper.rb +17 -4
  58. data/app/lib/primer/status/dsl.rb +43 -0
  59. data/app/lib/primer/test_selector_helper.rb +20 -0
  60. data/app/lib/primer/view_helper.rb +10 -12
  61. data/lib/primer/view_components/engine.rb +4 -0
  62. data/lib/primer/view_components/version.rb +1 -1
  63. data/static/statuses.json +1 -1
  64. metadata +37 -4
  65. data/app/lib/primer/view_helper/dsl.rb +0 -34
@@ -3,11 +3,13 @@
3
3
  module Primer
4
4
  # A basic wrapper component for most layout related needs.
5
5
  class BoxComponent < Primer::Component
6
+ status :stable
7
+
6
8
  # @example Default
7
9
  # <%= render(Primer::BoxComponent.new) { "Your content here" } %>
8
10
  #
9
11
  # @example Color and padding
10
- # <%= render(Primer::BoxComponent.new(bg: :gray, p: 3)) { "Hello world" } %>
12
+ # <%= render(Primer::BoxComponent.new(bg: :tertiary, p: 3)) { "Hello world" } %>
11
13
  #
12
14
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
13
15
  def initialize(**system_arguments)
@@ -18,9 +20,5 @@ module Primer
18
20
  def call
19
21
  render(Primer::BaseComponent.new(**@system_arguments)) { content }
20
22
  end
21
-
22
- def self.status
23
- Primer::Component::STATUSES[:stable]
24
- end
25
23
  end
26
24
  end
@@ -4,6 +4,7 @@ module Primer
4
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.
5
5
  class BreadcrumbComponent < Primer::Component
6
6
  include ViewComponent::SlotableV2
7
+ status :beta
7
8
 
8
9
  # _Note: if both `href` and `selected: true` are passed in, `href` will be ignored and the item will not be rendered as a link._
9
10
  #
@@ -9,19 +9,7 @@ module Primer
9
9
  include FetchOrFallbackHelper
10
10
  include OcticonsHelper
11
11
  include JoinStyleArgumentsHelper
12
- include ViewHelper::Dsl
13
12
  include ViewHelper
14
-
15
- # sourced from https://primer.style/doctocat/usage/front-matter#status
16
- STATUSES = {
17
- alpha: :alpha,
18
- beta: :beta,
19
- stable: :stable,
20
- deprecated: :deprecated
21
- }.freeze
22
-
23
- def self.status
24
- STATUSES[:alpha]
25
- end
13
+ include Status::Dsl
26
14
  end
27
15
  end
@@ -3,19 +3,30 @@
3
3
  module Primer
4
4
  # Use Primer::CounterComponent to add a count to navigational elements and buttons.
5
5
  class CounterComponent < Primer::Component
6
+ status :beta
7
+
6
8
  DEFAULT_SCHEME = :default
7
9
  SCHEME_MAPPINGS = {
8
- DEFAULT_SCHEME => "Counter",
9
- :gray => "Counter Counter--gray",
10
- :light_gray => "Counter Counter--gray-light"
10
+ DEFAULT_SCHEME => "",
11
+ :primary => "Counter--primary",
12
+ :secondary => "Counter--secondary",
13
+ # deprecated
14
+ :gray => "Counter--primary",
15
+ :light_gray => "Counter--secondary"
11
16
  }.freeze
17
+ DEPRECATED_SCHEME_OPTIONS = [:gray, :light_gray].freeze
18
+ SCHEME_OPTIONS = (SCHEME_MAPPINGS.keys - DEPRECATED_SCHEME_OPTIONS).freeze
12
19
 
13
20
  #
14
21
  # @example Default
15
22
  # <%= render(Primer::CounterComponent.new(count: 25)) %>
16
23
  #
24
+ # @example Schemes
25
+ # <%= render(Primer::CounterComponent.new(count: 25, scheme: :primary)) %>
26
+ # <%= render(Primer::CounterComponent.new(count: 25, scheme: :secondary)) %>
27
+ #
17
28
  # @param count [Integer, Float::INFINITY, nil] The number to be displayed (e.x. # of issues, pull requests)
18
- # @param scheme [Symbol] Color scheme. One of `SCHEME_MAPPINGS.keys`.
29
+ # @param scheme [Symbol] Color scheme. <%= one_of(Primer::CounterComponent::SCHEME_OPTIONS) %>
19
30
  # @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
31
  # @param hide_if_zero [Boolean] If true, a `hidden` attribute is added to the counter if `count` is zero.
21
32
  # @param text [String] Text to display instead of count.
@@ -41,8 +52,9 @@ module Primer
41
52
  @system_arguments[:title] = title
42
53
  @system_arguments[:tag] = :span
43
54
  @system_arguments[:classes] = class_names(
55
+ "Counter",
44
56
  @system_arguments[:classes],
45
- SCHEME_MAPPINGS[fetch_or_fallback(SCHEME_MAPPINGS.keys, scheme, DEFAULT_SCHEME)]
57
+ SCHEME_MAPPINGS[fetch_or_fallback(SCHEME_OPTIONS, scheme, DEFAULT_SCHEME, deprecated_values: DEPRECATED_SCHEME_OPTIONS)]
46
58
  )
47
59
  @system_arguments[:hidden] = true if count == 0 && hide_if_zero # rubocop:disable Style/NumericPredicate
48
60
  end
@@ -51,10 +63,6 @@ module Primer
51
63
  render(Primer::BaseComponent.new(**@system_arguments)) { value }
52
64
  end
53
65
 
54
- def self.status
55
- Primer::Component::STATUSES[:beta]
56
- end
57
-
58
66
  private
59
67
 
60
68
  def title
@@ -4,6 +4,7 @@ module Primer
4
4
  # Use DetailsComponent to reveal content after clicking a button.
5
5
  class DetailsComponent < Primer::Component
6
6
  include ViewComponent::SlotableV2
7
+ status :beta
7
8
 
8
9
  NO_OVERLAY = :none
9
10
  OVERLAY_MAPPINGS = {
@@ -16,12 +17,11 @@ module Primer
16
17
  #
17
18
  # @param button [Boolean] Whether to render the Summary as a button or not.
18
19
  # @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
20
+ renders_one :summary, lambda { |button: true, **system_arguments|
21
21
  system_arguments[:tag] = :summary
22
22
  system_arguments[:role] = "button"
23
23
 
24
- Primer::BaseComponent.new(**system_arguments) unless button
24
+ return Primer::BaseComponent.new(**system_arguments) unless button
25
25
 
26
26
  Primer::ButtonComponent.new(**system_arguments)
27
27
  }
@@ -5,6 +5,8 @@ module Primer
5
5
  # They're great for instances where you don't need the full power (and code)
6
6
  # of the select menu.
7
7
  class DropdownMenuComponent < Primer::Component
8
+ status :deprecated
9
+
8
10
  SCHEME_DEFAULT = :default
9
11
  SCHEME_MAPPINGS = {
10
12
  SCHEME_DEFAULT => "",
@@ -14,10 +16,6 @@ module Primer
14
16
  DIRECTION_DEFAULT = :se
15
17
  DIRECTION_OPTIONS = [DIRECTION_DEFAULT, :sw, :w, :e, :ne, :s].freeze
16
18
 
17
- def self.status
18
- STATUSES[:deprecated]
19
- end
20
-
21
19
  # @example With a header
22
20
  # <div>
23
21
  # <%= render(Primer::DetailsComponent.new(overlay: :default, reset: true, position: :relative)) do |c| %>
@@ -1,9 +1,9 @@
1
1
  <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
- <%= primer(:octicon, icon: @icon) if @icon %>
2
+ <%= primer_octicon icon: @icon if @icon %>
3
3
  <%= content %>
4
4
  <% if @dismissible %>
5
5
  <button class="flash-close js-flash-close" type="button" aria-label="Close">
6
- <%= primer(:octicon, icon: "x") %>
6
+ <%= primer_octicon icon: "x" %>
7
7
  </button>
8
8
  <% end %>
9
9
 
@@ -3,6 +3,8 @@
3
3
  module Primer
4
4
  # Use the Flash component to inform users of successful or pending actions.
5
5
  class FlashComponent < Primer::Component
6
+ status :beta
7
+
6
8
  include ViewComponent::SlotableV2
7
9
 
8
10
  # Optional action content showed on the right side of the component.
@@ -64,9 +66,5 @@ module Primer
64
66
  )
65
67
  @system_arguments[:mb] ||= spacious ? 4 : nil
66
68
  end
67
-
68
- def self.status
69
- Primer::Component::STATUSES[:beta]
70
- end
71
69
  end
72
70
  end
@@ -36,31 +36,31 @@ module Primer
36
36
  ALLOWED_DIRECTIONS = [DEFAULT_DIRECTION, :column, :column_reverse, :row, :row_reverse].freeze
37
37
 
38
38
  # @example Default
39
- # <%= render(Primer::FlexComponent.new(bg: :gray)) do %>
40
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 1" } %>
41
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 2" } %>
42
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 3" } %>
39
+ # <%= render(Primer::FlexComponent.new(bg: :tertiary)) do %>
40
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 1" } %>
41
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 2" } %>
42
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 3" } %>
43
43
  # <% end %>
44
44
  #
45
45
  # @example Justify center
46
- # <%= render(Primer::FlexComponent.new(justify_content: :center, bg: :gray)) do %>
47
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 1" } %>
48
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 2" } %>
49
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 3" } %>
46
+ # <%= render(Primer::FlexComponent.new(justify_content: :center, bg: :tertiary)) do %>
47
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 1" } %>
48
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 2" } %>
49
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 3" } %>
50
50
  # <% end %>
51
51
  #
52
52
  # @example Align end
53
- # <%= render(Primer::FlexComponent.new(align_items: :end, bg: :gray)) do %>
54
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 1" } %>
55
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 2" } %>
56
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 3" } %>
53
+ # <%= render(Primer::FlexComponent.new(align_items: :end, bg: :tertiary)) do %>
54
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 1" } %>
55
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 2" } %>
56
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 3" } %>
57
57
  # <% end %>
58
58
  #
59
59
  # @example Direction column
60
- # <%= render(Primer::FlexComponent.new(direction: :column, bg: :gray)) do %>
61
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 1" } %>
62
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 2" } %>
63
- # <%= render(Primer::BoxComponent.new(p: 5, bg: :gray_light, classes: "border")) { "Item 3" } %>
60
+ # <%= render(Primer::FlexComponent.new(direction: :column, bg: :tertiary)) do %>
61
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 1" } %>
62
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 2" } %>
63
+ # <%= render(Primer::BoxComponent.new(p: 5, bg: :secondary, classes: "border")) { "Item 3" } %>
64
64
  # <% end %>
65
65
  #
66
66
  # @param justify_content [Symbol] Use this param to distribute space between and around flex items along the main axis of the container. <%= one_of(Primer::FlexComponent::JUSTIFY_CONTENT_OPTIONS) %>
@@ -3,7 +3,7 @@
3
3
  module Primer
4
4
  # Use the Heading component to wrap a component that will create a heading element
5
5
  class HeadingComponent < Primer::Component
6
- view_helper :heading
6
+ status :beta
7
7
 
8
8
  # @example Default
9
9
  # <%= render(Primer::HeadingComponent.new) { "H1 Text" } %>
@@ -3,16 +3,21 @@
3
3
  module Primer
4
4
  # Use labels to add contextual metadata to a design.
5
5
  class LabelComponent < Primer::Component
6
+ status :beta
7
+
6
8
  SCHEME_MAPPINGS = {
7
9
  primary: "Label--primary",
8
10
  secondary: "Label--secondary",
9
11
  info: "Label--info",
10
12
  success: "Label--success",
11
13
  warning: "Label--warning",
12
- danger: "Label--danger"
14
+ danger: "Label--danger",
15
+ # deprecated
16
+ orange: "Label--orange",
17
+ purple: "Label--purple"
13
18
  }.freeze
14
-
15
- SCHEME_OPTIONS = SCHEME_MAPPINGS.keys << nil
19
+ DEPRECATED_SCHEME_OPTIONS = [:orange, :purple].freeze
20
+ SCHEME_OPTIONS = ([*SCHEME_MAPPINGS.keys, nil] - DEPRECATED_SCHEME_OPTIONS).freeze
16
21
 
17
22
  VARIANT_MAPPINGS = {
18
23
  large: "Label--large",
@@ -39,13 +44,12 @@ module Primer
39
44
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
40
45
  def initialize(title:, scheme: nil, variant: nil, **system_arguments)
41
46
  @system_arguments = system_arguments
42
- @system_arguments[:bg] = :blue if scheme.nil?
43
47
  @system_arguments[:tag] ||= :span
44
48
  @system_arguments[:title] = title
45
49
  @system_arguments[:classes] = class_names(
46
50
  "Label",
47
51
  system_arguments[:classes],
48
- SCHEME_MAPPINGS[fetch_or_fallback(SCHEME_OPTIONS, scheme)],
52
+ SCHEME_MAPPINGS[fetch_or_fallback(SCHEME_OPTIONS, scheme, deprecated_values: DEPRECATED_SCHEME_OPTIONS)],
49
53
  VARIANT_MAPPINGS[fetch_or_fallback(VARIANT_OPTIONS, variant)]
50
54
  )
51
55
  end
@@ -53,9 +57,5 @@ module Primer
53
57
  def call
54
58
  render(Primer::BaseComponent.new(**@system_arguments)) { content }
55
59
  end
56
-
57
- def self.status
58
- Primer::Component::STATUSES[:beta]
59
- end
60
60
  end
61
61
  end
@@ -1,17 +1,11 @@
1
1
  <%= render(Primer::FlexComponent.new(**@system_arguments)) do %>
2
2
  <% if @side == :left %>
3
- <%= render Primer::BaseComponent.new(tag: :div, classes: "flex-shrink-0", col: (@responsive ? [12, nil, @sidebar_col] : @sidebar_col), mb: (@responsive ? [4, nil, 0] : nil)) do %>
4
- <%= sidebar %>
5
- <% end %>
3
+ <%= sidebar %>
6
4
  <% end %>
7
5
 
8
- <%= render Primer::BaseComponent.new(tag: :div, classes: "flex-shrink-0", col: (@responsive ? [12, nil, @main_col] : @main_col), mb: (@responsive ? [4, nil, 0] : nil)) do %>
9
- <%= main %>
10
- <% end %>
6
+ <%= main %>
11
7
 
12
8
  <% if @side == :right %>
13
- <%= render Primer::BaseComponent.new(tag: :div, classes: "flex-shrink-0", col: (@responsive ? [12, nil, @sidebar_col] : @sidebar_col)) do %>
14
- <%= sidebar %>
15
- <% end %>
9
+ <%= sidebar %>
16
10
  <% end %>
17
11
  <% end %>
@@ -3,7 +3,32 @@
3
3
  module Primer
4
4
  # Use Layout to build a main/sidebar layout.
5
5
  class LayoutComponent < Primer::Component
6
- with_content_areas :main, :sidebar
6
+ include ViewComponent::SlotableV2
7
+
8
+ # The main content
9
+ #
10
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
11
+ renders_one :main, lambda { |**system_arguments|
12
+ system_arguments[:classes] = class_names("flex-shrink-0", system_arguments[:classes])
13
+ system_arguments[:col] = (@responsive ? [12, nil, @main_col] : @main_col)
14
+ system_arguments[:mb] = (@responsive ? [4, nil, 0] : nil)
15
+
16
+ Primer::BaseComponent.new(tag: :div, **system_arguments)
17
+ }
18
+
19
+ # The sidebar content
20
+ #
21
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
22
+ renders_one :sidebar, lambda { |**system_arguments|
23
+ system_arguments[:classes] = class_names("flex-shrink-0", system_arguments[:classes])
24
+ system_arguments[:col] = (@responsive ? [12, nil, @sidebar_col] : @sidebar_col)
25
+
26
+ if @side == :left
27
+ system_arguments[:mb] = (@responsive ? [4, nil, 0] : nil)
28
+ end
29
+
30
+ Primer::BaseComponent.new(tag: :div, **system_arguments)
31
+ }
7
32
 
8
33
  DEFAULT_SIDE = :right
9
34
  ALLOWED_SIDES = [DEFAULT_SIDE, :left].freeze
@@ -14,14 +39,14 @@ module Primer
14
39
 
15
40
  # @example Default
16
41
  # <%= render(Primer::LayoutComponent.new) do |component| %>
17
- # <% component.with(:sidebar) { "Sidebar" } %>
18
- # <% component.with(:main) { "Main" } %>
42
+ # <% component.sidebar { "Sidebar" } %>
43
+ # <% component.main { "Main" } %>
19
44
  # <% end %>
20
45
  #
21
46
  # @example Left sidebar
22
47
  # <%= render(Primer::LayoutComponent.new(side: :left)) do |component| %>
23
- # <% component.with(:sidebar) { "Sidebar" } %>
24
- # <% component.with(:main) { "Main" } %>
48
+ # <% component.sidebar { "Sidebar" } %>
49
+ # <% component.main { "Main" } %>
25
50
  # <% end %>
26
51
  #
27
52
  # @param responsive [Boolean] Whether to collapse layout to a single column at smaller widths.
@@ -3,22 +3,50 @@
3
3
  module Primer
4
4
  # Use links for moving from one page to another. The Link component styles anchor tags with default blue styling and hover text-decoration.
5
5
  class LinkComponent < Primer::Component
6
+ status :beta
7
+
8
+ DEFAULT_VARIANT = :default
9
+ VARIANT_MAPPINGS = {
10
+ DEFAULT_VARIANT => "",
11
+ :primary => "Link--primary",
12
+ :secondary => "Link--secondary"
13
+ }.freeze
14
+
15
+ DEFAULT_TAG = :a
16
+ TAG_OPTIONS = [DEFAULT_TAG, :span].freeze
17
+
6
18
  # @example Default
7
- # <%= render(Primer::LinkComponent.new(href: "http://www.google.com")) { "Link" } %>
19
+ # <%= render(Primer::LinkComponent.new(href: "#")) { "Link" } %>
8
20
  #
9
21
  # @example Muted
10
- # <%= render(Primer::LinkComponent.new(href: "http://www.google.com", muted: true)) { "Link" } %>
22
+ # <%= render(Primer::LinkComponent.new(href: "#", muted: true)) { "Link" } %>
23
+ #
24
+ # @example Variants
25
+ # <%= render(Primer::LinkComponent.new(href: "#", variant: :primary)) { "Primary" } %>
26
+ # <%= render(Primer::LinkComponent.new(href: "#", variant: :secondary)) { "Secondary" } %>
27
+ #
28
+ # @example Without underline
29
+ # <%= render(Primer::LinkComponent.new(href: "#", underline: false)) { "Link" } %>
30
+ #
31
+ # @example Span as link
32
+ # <%= render(Primer::LinkComponent.new(tag: :span)) { "Span as a link" } %>
11
33
  #
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
34
+ # @param tag [String] <%= one_of(Primer::LinkComponent::TAG_OPTIONS) %>
35
+ # @param href [String] URL to be used for the Link. Required if tag is `:a`. If the requirements are not met an error will be raised in non production environments. In production, an empty link element will be rendered.
36
+ # @param variant [Symbol] <%= one_of(Primer::LinkComponent::VARIANT_MAPPINGS.keys) %>
37
+ # @param muted [Boolean] Uses light gray for Link color, and blue on hover.
38
+ # @param underline [Boolean] Whether or not to underline the link.
14
39
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
15
- def initialize(href:, muted: false, **system_arguments)
40
+ def initialize(href: nil, tag: DEFAULT_TAG, variant: DEFAULT_VARIANT, muted: false, underline: true, **system_arguments)
16
41
  @system_arguments = system_arguments
17
- @system_arguments[:tag] = :a
42
+ @system_arguments[:tag] = fetch_or_fallback(TAG_OPTIONS, tag, DEFAULT_TAG)
18
43
  @system_arguments[:href] = href
19
44
  @system_arguments[:classes] = class_names(
20
45
  @system_arguments[:classes],
21
- "muted-link" => fetch_or_fallback_boolean(muted, false)
46
+ VARIANT_MAPPINGS[fetch_or_fallback(VARIANT_MAPPINGS.keys, variant, DEFAULT_VARIANT)],
47
+ "Link" => tag == :span,
48
+ "Link--muted" => muted,
49
+ "no-underline" => !underline
22
50
  )
23
51
  end
24
52
 
@@ -26,8 +54,8 @@ module Primer
26
54
  render(Primer::BaseComponent.new(**@system_arguments)) { content }
27
55
  end
28
56
 
29
- def self.status
30
- Primer::Component::STATUSES[:beta]
57
+ def before_render
58
+ raise ArgumentError, "href is required when using <a> tag" if @system_arguments[:tag] == :a && @system_arguments[:href].nil? && !Rails.env.production?
31
59
  end
32
60
  end
33
61
  end
@@ -3,9 +3,10 @@
3
3
  module Primer
4
4
  # Renders an [Octicon](https://primer.style/octicons/) with <%= link_to_system_arguments_docs %>.
5
5
  class OcticonComponent < Primer::Component
6
- view_helper :octicon
6
+ status :beta
7
7
 
8
- include Primer::ClassNameHelper
8
+ include ClassNameHelper
9
+ include TestSelectorHelper
9
10
  include OcticonsHelper
10
11
 
11
12
  SIZE_DEFAULT = :small
@@ -38,15 +39,11 @@ module Primer
38
39
  # Filter out classify options to prevent them from becoming invalid html attributes.
39
40
  # Note height and width are both classify options and valid html attributes.
40
41
  octicon_helper_options = @system_arguments.slice(:height, :width)
41
- @system_arguments = @system_arguments.except(*Primer::Classify::VALID_KEYS, :classes).merge(octicon_helper_options)
42
+ @system_arguments = add_test_selector(@system_arguments).except(*Primer::Classify::VALID_KEYS, :classes).merge(octicon_helper_options)
42
43
  end
43
44
 
44
45
  def call
45
46
  octicon(@icon, { **@system_arguments })
46
47
  end
47
-
48
- def self.status
49
- Primer::Component::STATUSES[:beta]
50
- end
51
48
  end
52
49
  end