primer_view_components 0.0.34 → 0.0.39

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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +131 -21
  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/components/primer/{auto_complete_component.rb → auto_complete.rb} +14 -12
  6. data/app/components/primer/{auto_complete_component.d.ts → auto_complete/auto_complete.d.ts} +0 -0
  7. data/app/components/primer/{auto_complete_component.html.erb → auto_complete/auto_complete.html.erb} +0 -0
  8. data/app/components/primer/{auto_complete_component.js → auto_complete/auto_complete.js} +0 -0
  9. data/app/components/primer/{auto_complete_component.ts → auto_complete/auto_complete.ts} +0 -0
  10. data/app/components/primer/auto_complete/auto_component.d.ts +1 -0
  11. data/app/components/primer/auto_complete/auto_component.js +1 -0
  12. data/app/components/primer/auto_complete/item.rb +42 -0
  13. data/app/components/primer/avatar_component.rb +22 -3
  14. data/app/components/primer/avatar_stack_component.rb +3 -1
  15. data/app/components/primer/base_button.rb +47 -0
  16. data/app/components/primer/base_component.rb +7 -8
  17. data/app/components/primer/blankslate_component.rb +4 -1
  18. data/app/components/primer/border_box_component.rb +1 -1
  19. data/app/components/primer/box_component.rb +1 -1
  20. data/app/components/primer/breadcrumb_component.rb +1 -1
  21. data/app/components/primer/button_component.html.erb +9 -0
  22. data/app/components/primer/button_component.rb +60 -21
  23. data/app/components/primer/{button_group_component.html.erb → button_group.html.erb} +0 -0
  24. data/app/components/primer/button_group.rb +61 -0
  25. data/app/components/primer/button_marketing_component.rb +4 -9
  26. data/app/components/primer/clipboard_copy.html.erb +8 -0
  27. data/app/components/primer/clipboard_copy.rb +26 -0
  28. data/app/components/primer/clipboard_copy_component.d.ts +1 -0
  29. data/app/components/primer/clipboard_copy_component.js +23 -0
  30. data/app/components/primer/clipboard_copy_component.ts +26 -0
  31. data/app/components/primer/close_button.rb +39 -0
  32. data/app/components/primer/component.rb +17 -2
  33. data/app/components/primer/counter_component.rb +1 -1
  34. data/app/components/primer/details_component.rb +1 -1
  35. data/app/components/primer/dropdown/menu_component.rb +1 -1
  36. data/app/components/primer/dropdown_component.rb +2 -2
  37. data/app/components/primer/dropdown_menu_component.rb +1 -1
  38. data/app/components/primer/flash_component.rb +1 -1
  39. data/app/components/primer/flex_component.rb +1 -1
  40. data/app/components/primer/flex_item_component.rb +20 -1
  41. data/app/components/primer/heading_component.rb +32 -4
  42. data/app/components/primer/hidden_text_expander.rb +41 -0
  43. data/app/components/primer/icon_button.rb +48 -0
  44. data/app/components/primer/label_component.rb +1 -1
  45. data/app/components/primer/layout_component.rb +1 -1
  46. data/app/components/primer/link_component.rb +1 -1
  47. data/app/components/primer/markdown_component.rb +1 -1
  48. data/app/components/primer/menu_component.rb +1 -1
  49. data/app/components/primer/navigation/tab_component.html.erb +9 -7
  50. data/app/components/primer/navigation/tab_component.rb +27 -3
  51. data/app/components/primer/octicon_component.rb +35 -14
  52. data/app/components/primer/popover_component.rb +1 -1
  53. data/app/components/primer/primer.d.ts +2 -1
  54. data/app/components/primer/primer.js +2 -1
  55. data/app/components/primer/primer.ts +2 -1
  56. data/app/components/primer/progress_bar_component.rb +1 -1
  57. data/app/components/primer/spinner_component.rb +1 -1
  58. data/app/components/primer/state_component.rb +2 -2
  59. data/app/components/primer/subhead_component.rb +1 -1
  60. data/app/components/primer/tab_container_component.rb +1 -1
  61. data/app/components/primer/tab_nav_component.html.erb +2 -2
  62. data/app/components/primer/tab_nav_component.rb +23 -9
  63. data/app/components/primer/text_component.rb +1 -1
  64. data/app/components/primer/time_ago_component.rb +1 -1
  65. data/app/components/primer/timeline_item_component.rb +1 -1
  66. data/app/components/primer/tooltip_component.rb +1 -1
  67. data/app/components/primer/{truncate_component.rb → truncate.rb} +8 -6
  68. data/app/components/primer/underline_nav_component.rb +47 -15
  69. data/app/lib/primer/classify.rb +8 -33
  70. data/app/lib/primer/classify/cache.rb +19 -14
  71. data/app/lib/primer/classify/flex.rb +111 -0
  72. data/app/lib/primer/classify/functional_border_colors.rb +1 -2
  73. data/app/lib/primer/fetch_or_fallback_helper.rb +2 -2
  74. data/app/lib/primer/octicon/cache.rb +38 -0
  75. data/app/lib/primer/tabbed_component_helper.rb +4 -0
  76. data/lib/primer/view_components/version.rb +1 -1
  77. data/static/statuses.json +1 -1
  78. metadata +116 -32
  79. data/app/assets/javascripts/primer_view_components.js.map.orig +0 -5
  80. data/app/assets/javascripts/primer_view_components.js.orig +0 -6
  81. data/app/components/primer/auto_complete_item_component.rb +0 -38
  82. data/app/components/primer/button_group_component.rb +0 -35
@@ -1,14 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "octicons"
4
+
3
5
  module Primer
4
- # Renders an [Octicon](https://primer.style/octicons/) with <%= link_to_system_arguments_docs %>.
6
+ # `Octicon` renders an <%= link_to_octicons %> with <%= link_to_system_arguments_docs %>.
5
7
  class OcticonComponent < Primer::Component
6
8
  status :beta
7
9
 
8
- include ClassNameHelper
9
- include TestSelectorHelper
10
- include OcticonsHelper
11
-
12
10
  SIZE_DEFAULT = :small
13
11
  SIZE_MAPPINGS = {
14
12
  SIZE_DEFAULT => 16,
@@ -27,24 +25,47 @@ module Primer
27
25
  # @example Large
28
26
  # <%= render(Primer::OcticonComponent.new("x", size: :large)) %>
29
27
  #
30
- # @param icon [String] Name of [Octicon](https://primer.style/octicons/) to use.
28
+ # @param icon [String] Name of <%= link_to_octicons %> to use.
31
29
  # @param size [Symbol] <%= one_of(Primer::OcticonComponent::SIZE_MAPPINGS) %>
32
30
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
33
31
  def initialize(icon_name = nil, icon: nil, size: SIZE_DEFAULT, **system_arguments)
34
- @icon = icon_name || icon
32
+ icon_key = icon_name || icon
33
+ cache_key = [icon_key, size, system_arguments.slice(:height, :width)].join("_")
34
+
35
35
  @system_arguments = system_arguments
36
+ @system_arguments[:tag] = :svg
37
+ @system_arguments[:aria] ||= {}
36
38
 
37
- @system_arguments[:class] = Primer::Classify.call(**@system_arguments)[:class]
38
- @system_arguments[:height] ||= SIZE_MAPPINGS[size]
39
+ if @system_arguments[:aria][:label] || @system_arguments[:"aria-label"]
40
+ @system_arguments[:role] = "img"
41
+ else
42
+ @system_arguments[:aria][:hidden] = true
43
+ end
39
44
 
40
- # Filter out classify options to prevent them from becoming invalid html attributes.
41
- # Note height and width are both classify options and valid html attributes.
42
- octicon_helper_options = @system_arguments.slice(:height, :width)
43
- @system_arguments = add_test_selector(@system_arguments).except(*Primer::Classify::VALID_KEYS, :classes).merge(octicon_helper_options)
45
+ if (cache_icon = Primer::Octicon::Cache.read(cache_key))
46
+ @icon = cache_icon
47
+ else
48
+ # Filter out classify options to prevent them from becoming invalid html attributes.
49
+ # Note height and width are both classify options and valid html attributes.
50
+ octicon_options = {
51
+ height: SIZE_MAPPINGS[fetch_or_fallback(SIZE_OPTIONS, size, SIZE_DEFAULT)]
52
+ }.merge(@system_arguments.slice(:height, :width))
53
+
54
+ @icon = Octicons::Octicon.new(icon_key, octicon_options)
55
+ Primer::Octicon::Cache.set(cache_key, @icon)
56
+ end
57
+
58
+ @system_arguments[:classes] = class_names(
59
+ @icon.options[:class],
60
+ @system_arguments[:classes]
61
+ )
62
+ @system_arguments.merge!(@icon.options.except(:class, :'aria-hidden'))
44
63
  end
45
64
 
46
65
  def call
47
- octicon(@icon, { **@system_arguments })
66
+ render(Primer::BaseComponent.new(**@system_arguments)) { @icon.path.html_safe } # rubocop:disable Rails/OutputSafety
48
67
  end
68
+
69
+ Primer::Octicon::Cache.preload!
49
70
  end
50
71
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Use popovers to bring attention to specific user interface elements, typically to suggest an action or to guide users through a new experience.
4
+ # Use `Popover` to bring attention to specific user interface elements, typically to suggest an action or to guide users through a new experience.
5
5
  #
6
6
  # By default, the popover renders with absolute positioning, meaning it should usually be wrapped in an element with a relative position in order to be positioned properly. To render the popover with relative positioning, use the relative property.
7
7
  class PopoverComponent < Primer::Component
@@ -1,3 +1,4 @@
1
- import './auto_complete_component';
1
+ import './auto_complete/auto_complete';
2
+ import './clipboard_copy_component';
2
3
  import './tab_container_component';
3
4
  import './time_ago_component';
@@ -1,3 +1,4 @@
1
- import './auto_complete_component';
1
+ import './auto_complete/auto_complete';
2
+ import './clipboard_copy_component';
2
3
  import './tab_container_component';
3
4
  import './time_ago_component';
@@ -1,3 +1,4 @@
1
- import './auto_complete_component'
1
+ import './auto_complete/auto_complete'
2
+ import './clipboard_copy_component'
2
3
  import './tab_container_component'
3
4
  import './time_ago_component'
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Use ProgressBar to visualize task completion.
4
+ # Use `ProgressBar` to visualize task completion.
5
5
  class ProgressBarComponent < Primer::Component
6
6
  status :beta
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Use Primer::SpinnerComponent to let users know that content is being loaded.
4
+ # Use `Spinner` to let users know that content is being loaded.
5
5
  class SpinnerComponent < Primer::Component
6
6
  status :beta
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Component for rendering the status of an item.
4
+ # Use `State` for rendering the status of an item.
5
5
  class StateComponent < Primer::Component
6
6
  status :beta
7
7
 
@@ -29,7 +29,7 @@ module Primer
29
29
  SIZE_OPTIONS = SIZE_MAPPINGS.keys
30
30
 
31
31
  TAG_DEFAULT = :span
32
- TAG_OPTIONS = [TAG_DEFAULT, :div, :a].freeze
32
+ TAG_OPTIONS = [TAG_DEFAULT, :div].freeze
33
33
 
34
34
  # @example Default
35
35
  # <%= render(Primer::StateComponent.new(title: "title")) { "State" } %>
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Use the Subhead component for page headings.
4
+ # Use `Subhead` for page headings.
5
5
  class SubheadComponent < Primer::Component
6
6
  status :beta
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Use TabContainer to create tabbed content with keyboard support. This component does not add any styles.
4
+ # Use `TabContainer` to create tabbed content with keyboard support. This component does not add any styles.
5
5
  # It only provides the tab functionality. If you want styled Tabs you can look at <%= link_to_component(Primer::TabNavComponent) %>.
6
6
  #
7
7
  # This component requires javascript.
@@ -1,10 +1,10 @@
1
1
  <%= wrapper do %>
2
2
  <%= render Primer::BaseComponent.new(**@system_arguments) do %>
3
- <nav role="tablist" aria-label="<%= @aria_label %>" class="tabnav-tabs">
3
+ <%= render Primer::BaseComponent.new(**@body_arguments) do %>
4
4
  <% tabs.each do |tab| %>
5
5
  <%= tab %>
6
6
  <% end %>
7
- </nav>
7
+ <% end %>
8
8
  <% end %>
9
9
 
10
10
  <% if @with_panel %>
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Use TabNav to style navigation with a tab-based selected state, typically used for navigation placed at the top of the page.
4
+ # Use `TabNav` to style navigation with a tab-based selected state, typically used for navigation placed at the top of the page.
5
5
  class TabNavComponent < Primer::Component
6
6
  include Primer::TabbedComponentHelper
7
7
 
@@ -14,18 +14,23 @@ module Primer
14
14
  "tabnav-tab",
15
15
  system_arguments[:classes]
16
16
  )
17
- Primer::Navigation::TabComponent.new(selected: selected, with_panel: @with_panel, **system_arguments)
17
+
18
+ Primer::Navigation::TabComponent.new(
19
+ selected: selected,
20
+ with_panel: @with_panel,
21
+ **system_arguments
22
+ )
18
23
  }
19
24
 
20
25
  # @example Default
21
- # <%= render(Primer::TabNavComponent.new) do |c| %>
26
+ # <%= render(Primer::TabNavComponent.new(label: "Default")) do |c| %>
22
27
  # <% c.tab(selected: true, href: "#") { "Tab 1" }%>
23
28
  # <% c.tab(href: "#") { "Tab 2" } %>
24
29
  # <% c.tab(href: "#") { "Tab 3" } %>
25
30
  # <% end %>
26
31
  #
27
32
  # @example With icons and counters
28
- # <%= render(Primer::TabNavComponent.new) do |component| %>
33
+ # <%= render(Primer::TabNavComponent.new(label: "With icons and counters")) do |component| %>
29
34
  # <% component.tab(href: "#", selected: true) do |t| %>
30
35
  # <% t.icon(icon: :star) %>
31
36
  # <% t.text { "Item 1" } %>
@@ -42,7 +47,7 @@ module Primer
42
47
  # <% end %>
43
48
  #
44
49
  # @example With panels
45
- # <%= render(Primer::TabNavComponent.new(with_panel: true)) do |c| %>
50
+ # <%= render(Primer::TabNavComponent.new(label: "With panels", with_panel: true)) do |c| %>
46
51
  # <% c.tab(selected: true) do |t| %>
47
52
  # <% t.text { "Tab 1" } %>
48
53
  # <% t.panel do %>
@@ -63,19 +68,28 @@ module Primer
63
68
  # <% end %>
64
69
  # <% end %>
65
70
  #
66
- # @param aria_label [String] Used to set the `aria-label` on the top level `<nav>` element.
71
+ # @param label [String] Used to set the `aria-label` on the top level `<nav>` element.
67
72
  # @param with_panel [Boolean] Whether the TabNav should navigate through pages or panels.
68
73
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
69
- def initialize(aria_label: nil, with_panel: false, **system_arguments)
70
- @aria_label = aria_label
74
+ def initialize(label:, with_panel: false, **system_arguments)
71
75
  @with_panel = with_panel
72
76
  @system_arguments = system_arguments
73
- @system_arguments[:tag] ||= :div
74
77
 
78
+ @system_arguments[:tag] ||= :div
75
79
  @system_arguments[:classes] = class_names(
76
80
  "tabnav",
77
81
  system_arguments[:classes]
78
82
  )
83
+
84
+ @body_arguments = {
85
+ tag: navigation_tag(with_panel),
86
+ classes: "tabnav-tabs",
87
+ aria: {
88
+ label: label
89
+ }
90
+ }
91
+
92
+ @body_arguments[:role] = :tablist if @with_panel
79
93
  end
80
94
  end
81
95
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # The Text component is a wrapper component that will apply typography styles to the text inside.
4
+ # `Text` is a wrapper component that will apply typography styles to the text inside.
5
5
  class TextComponent < Primer::Component
6
6
  status :beta
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Use Primer::TimeAgoComponent to display a time relative to how long ago it was. This component requires JavaScript.
4
+ # Use `TimeAgo` to display a time relative to how long ago it was. This component requires JavaScript.
5
5
  class TimeAgoComponent < Primer::Component
6
6
  status :beta
7
7
 
@@ -19,7 +19,7 @@ module Primer
19
19
 
20
20
  # Badge that will be connected to other TimelineItems.
21
21
  #
22
- # @param icon [String] Name of [Octicon](https://primer.style/octicons/) to use.
22
+ # @param icon [String] Name of <%= link_to_octicons %> to use.
23
23
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
24
24
  renders_one :badge, "BadgeComponent"
25
25
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # The Tooltip component is a wrapper component that will apply a tooltip to the provided content.
4
+ # `Tooltip` is a wrapper component that will apply a tooltip to the provided content.
5
5
  class TooltipComponent < Primer::Component
6
6
  DIRECTION_DEFAULT = :n
7
7
  ALIGN_DEFAULT = :default
@@ -1,21 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Use TruncateComponent to shorten overflowing text with an ellipsis.
5
- class TruncateComponent < Primer::Component
4
+ # Use `Truncate` to shorten overflowing text with an ellipsis.
5
+ class Truncate < Primer::Component
6
+ status :beta
7
+
6
8
  # @example Default
7
9
  # <div class="col-2">
8
- # <%= render(Primer::TruncateComponent.new(tag: :p)) { "branch-name-that-is-really-long" } %>
10
+ # <%= render(Primer::Truncate.new(tag: :p)) { "branch-name-that-is-really-long" } %>
9
11
  # </div>
10
12
  #
11
13
  # @example Inline
12
- # <%= render(Primer::TruncateComponent.new(tag: :span, inline: true)) { "branch-name-that-is-really-long" } %>
14
+ # <%= render(Primer::Truncate.new(tag: :span, inline: true)) { "branch-name-that-is-really-long" } %>
13
15
  #
14
16
  # @example Expandable
15
- # <%= render(Primer::TruncateComponent.new(tag: :span, inline: true, expandable: true)) { "branch-name-that-is-really-long" } %>
17
+ # <%= render(Primer::Truncate.new(tag: :span, inline: true, expandable: true)) { "branch-name-that-is-really-long" } %>
16
18
  #
17
19
  # @example Custom size
18
- # <%= render(Primer::TruncateComponent.new(tag: :span, inline: true, expandable: true, max_width: 100)) { "branch-name-that-is-really-long" } %>
20
+ # <%= render(Primer::Truncate.new(tag: :span, inline: true, expandable: true, max_width: 100)) { "branch-name-that-is-really-long" } %>
19
21
  #
20
22
  # @param inline [Boolean] Whether the element is inline (or inline-block).
21
23
  # @param expandable [Boolean] Whether the entire string should be revealed on hover. Can only be used in conjunction with `inline`.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Primer
4
- # Use the UnderlineNav component to style navigation with a minimal
4
+ # Use `UnderlineNav` to style navigation with a minimal
5
5
  # underlined selected state, typically used for navigation placed at the top
6
6
  # of the page.
7
7
  class UnderlineNavComponent < Primer::Component
@@ -10,6 +10,9 @@ module Primer
10
10
  ALIGN_DEFAULT = :left
11
11
  ALIGN_OPTIONS = [ALIGN_DEFAULT, :right].freeze
12
12
 
13
+ BODY_TAG_DEFAULT = :div
14
+ BODY_TAG_OPTIONS = [BODY_TAG_DEFAULT, :ul].freeze
15
+
13
16
  # Use the tabs to list navigation items. For more information, refer to <%= link_to_component(Primer::Navigation::TabComponent) %>.
14
17
  #
15
18
  # @param selected [Boolean] Whether the tab is selected.
@@ -19,7 +22,9 @@ module Primer
19
22
  "UnderlineNav-item",
20
23
  system_arguments[:classes]
21
24
  )
25
+
22
26
  Primer::Navigation::TabComponent.new(
27
+ list: list?,
23
28
  selected: selected,
24
29
  with_panel: @with_panel,
25
30
  icon_classes: "UnderlineNav-octicon",
@@ -38,7 +43,7 @@ module Primer
38
43
  }
39
44
 
40
45
  # @example Default
41
- # <%= render(Primer::UnderlineNavComponent.new) do |component| %>
46
+ # <%= render(Primer::UnderlineNavComponent.new(label: "Default")) do |component| %>
42
47
  # <% component.tab(href: "#", selected: true) { "Item 1" } %>
43
48
  # <% component.tab(href: "#") { "Item 2" } %>
44
49
  # <% component.actions do %>
@@ -47,7 +52,7 @@ module Primer
47
52
  # <% end %>
48
53
  #
49
54
  # @example With icons and counters
50
- # <%= render(Primer::UnderlineNavComponent.new) do |component| %>
55
+ # <%= render(Primer::UnderlineNavComponent.new(label: "With icons and counters")) do |component| %>
51
56
  # <% component.tab(href: "#", selected: true) do |t| %>
52
57
  # <% t.icon(icon: :star) %>
53
58
  # <% t.text { "Item 1" } %>
@@ -67,7 +72,20 @@ module Primer
67
72
  # <% end %>
68
73
  #
69
74
  # @example Align right
70
- # <%= render(Primer::UnderlineNavComponent.new(align: :right)) do |component| %>
75
+ # <%= render(Primer::UnderlineNavComponent.new(label: "Align right", align: :right)) do |component| %>
76
+ # <% component.tab(href: "#", selected: true) do |t| %>
77
+ # <% t.text { "Item 1" } %>
78
+ # <% end %>
79
+ # <% component.tab(href: "#") do |t| %>
80
+ # <% t.text { "Item 2" } %>
81
+ # <% end %>
82
+ # <% component.actions do %>
83
+ # <%= render(Primer::ButtonComponent.new) { "Button!" } %>
84
+ # <% end %>
85
+ # <% end %>
86
+ #
87
+ # @example As a list
88
+ # <%= render(Primer::UnderlineNavComponent.new(label: "As a list", body_arguments: { tag: :ul })) do |component| %>
71
89
  # <% component.tab(href: "#", selected: true) do |t| %>
72
90
  # <% t.text { "Item 1" } %>
73
91
  # <% end %>
@@ -80,7 +98,7 @@ module Primer
80
98
  # <% end %>
81
99
  #
82
100
  # @example With panels
83
- # <%= render(Primer::UnderlineNavComponent.new(with_panel: true)) do |component| %>
101
+ # <%= render(Primer::UnderlineNavComponent.new(label: "With panels", with_panel: true)) do |component| %>
84
102
  # <% component.tab(selected: true) do |t| %>
85
103
  # <% t.text { "Item 1" } %>
86
104
  # <% t.panel do %>
@@ -98,33 +116,47 @@ module Primer
98
116
  # <% end %>
99
117
  # <% end %>
100
118
  #
119
+ # @param label [String] The `aria-label` on top level `<nav>` element.
101
120
  # @param with_panel [Boolean] Whether the TabNav should navigate through pages or panels.
102
121
  # @param align [Symbol] <%= one_of(Primer::UnderlineNavComponent::ALIGN_OPTIONS) %> - Defaults to <%= Primer::UnderlineNavComponent::ALIGN_DEFAULT %>
122
+ # @param body_arguments [Hash] <%= link_to_system_arguments_docs %> for the body wrapper.
103
123
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
104
- def initialize(with_panel: false, align: ALIGN_DEFAULT, body_classes: "", **system_arguments)
124
+ def initialize(label:, with_panel: false, align: ALIGN_DEFAULT, body_arguments: { tag: BODY_TAG_DEFAULT }, **system_arguments)
105
125
  @with_panel = with_panel
106
126
  @align = fetch_or_fallback(ALIGN_OPTIONS, align, ALIGN_DEFAULT)
107
127
 
108
128
  @system_arguments = system_arguments
109
- @system_arguments[:tag] = :nav
110
- @system_arguments[:role] = :tablist
129
+ @system_arguments[:tag] = navigation_tag(with_panel)
111
130
  @system_arguments[:classes] = class_names(
112
131
  @system_arguments[:classes],
113
132
  "UnderlineNav",
114
133
  "UnderlineNav--right" => @align == :right
115
134
  )
116
135
 
117
- @body_arguments = {
118
- tag: :div,
119
- classes: class_names(
120
- "UnderlineNav-body",
121
- body_classes
122
- )
123
- }
136
+ @body_arguments = body_arguments
137
+ @body_tag = fetch_or_fallback(BODY_TAG_OPTIONS, body_arguments[:tag]&.to_sym, BODY_TAG_DEFAULT)
138
+
139
+ @body_arguments[:tag] = @body_tag
140
+ @body_arguments[:classes] = class_names(
141
+ "UnderlineNav-body",
142
+ @body_arguments[:classes],
143
+ "list-style-none" => list?
144
+ )
145
+
146
+ if with_panel
147
+ @body_arguments[:role] = :tablist
148
+ @body_arguments[:"aria-label"] = label
149
+ else
150
+ @system_arguments[:"aria-label"] = label
151
+ end
124
152
  end
125
153
 
126
154
  private
127
155
 
156
+ def list?
157
+ @body_tag == :ul
158
+ end
159
+
128
160
  def body
129
161
  Primer::BaseComponent.new(**@body_arguments)
130
162
  end