primer_view_components 0.0.31 → 0.0.36
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +94 -0
- data/README.md +2 -2
- data/app/components/primer/{auto_complete_component.rb → auto_complete.rb} +12 -12
- data/app/components/primer/{auto_complete_component.d.ts → auto_complete/auto_complete.d.ts} +0 -0
- data/app/components/primer/{auto_complete_component.html.erb → auto_complete/auto_complete.html.erb} +0 -0
- data/app/components/primer/{auto_complete_component.js → auto_complete/auto_complete.js} +0 -0
- data/app/components/primer/{auto_complete_component.ts → auto_complete/auto_complete.ts} +0 -0
- data/app/components/primer/auto_complete/auto_component.d.ts +1 -0
- data/app/components/primer/auto_complete/auto_component.js +1 -0
- data/app/components/primer/auto_complete/item.rb +42 -0
- data/app/components/primer/avatar_stack_component.rb +1 -1
- data/app/components/primer/base_component.rb +115 -85
- data/app/components/primer/blankslate_component.html.erb +1 -1
- data/app/components/primer/blankslate_component.rb +0 -2
- data/app/components/primer/border_box_component.rb +0 -2
- data/app/components/primer/breadcrumb_component.rb +0 -1
- data/app/components/primer/button_component.rb +37 -16
- data/app/components/primer/button_group_component.rb +3 -5
- data/app/components/primer/button_marketing_component.rb +12 -12
- data/app/components/primer/close_button.rb +30 -0
- data/app/components/primer/component.rb +3 -0
- data/app/components/primer/details_component.rb +0 -1
- data/app/components/primer/dropdown/menu_component.rb +0 -2
- data/app/components/primer/dropdown_component.rb +1 -3
- data/app/components/primer/dropdown_menu_component.rb +1 -1
- data/app/components/primer/flash_component.html.erb +2 -2
- data/app/components/primer/flash_component.rb +10 -12
- data/app/components/primer/foo_bar.d.ts +1 -0
- data/app/components/primer/foo_bar.js +1 -0
- data/app/components/primer/hidden_text_expander.rb +43 -0
- data/app/components/primer/layout_component.rb +0 -2
- data/app/components/primer/link_component.rb +9 -9
- data/app/components/primer/menu_component.rb +2 -4
- data/app/components/primer/navigation/tab_component.html.erb +11 -0
- data/app/components/primer/navigation/tab_component.rb +126 -0
- data/app/components/primer/octicon_component.rb +5 -8
- data/app/components/primer/popover_component.rb +0 -1
- data/app/components/primer/primer.d.ts +1 -1
- data/app/components/primer/primer.js +1 -1
- data/app/components/primer/primer.ts +1 -1
- data/app/components/primer/progress_bar_component.rb +0 -1
- data/app/components/primer/spinner_component.html.erb +1 -3
- data/app/components/primer/spinner_component.rb +1 -0
- data/app/components/primer/state_component.rb +13 -13
- data/app/components/primer/subhead_component.rb +1 -3
- data/app/components/primer/tab_nav_component.html.erb +8 -10
- data/app/components/primer/tab_nav_component.rb +63 -76
- data/app/components/primer/time_ago_component.rb +2 -1
- data/app/components/primer/timeline_item_component.rb +1 -2
- data/app/components/primer/{truncate_component.rb → truncate.rb} +8 -6
- data/app/components/primer/underline_nav_component.html.erb +19 -7
- data/app/components/primer/underline_nav_component.rb +114 -16
- data/app/lib/primer/classify.rb +5 -14
- data/app/lib/primer/classify/cache.rb +14 -4
- data/app/lib/primer/classify/spacing.rb +63 -0
- data/app/lib/primer/tabbed_component_helper.rb +39 -0
- data/app/lib/primer/view_helper.rb +2 -2
- data/lib/primer/view_components/version.rb +1 -1
- data/static/statuses.json +1 -1
- metadata +110 -31
- data/app/assets/javascripts/primer_view_components.js.map.orig +0 -5
- data/app/assets/javascripts/primer_view_components.js.orig +0 -6
- data/app/components/primer/auto_complete_item_component.rb +0 -40
- data/app/components/primer/slot.rb +0 -10
@@ -5,9 +5,9 @@ module Primer
|
|
5
5
|
class LinkComponent < Primer::Component
|
6
6
|
status :beta
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
DEFAULT_SCHEME = :default
|
9
|
+
SCHEME_MAPPINGS = {
|
10
|
+
DEFAULT_SCHEME => "",
|
11
11
|
:primary => "Link--primary",
|
12
12
|
:secondary => "Link--secondary"
|
13
13
|
}.freeze
|
@@ -21,9 +21,9 @@ module Primer
|
|
21
21
|
# @example Muted
|
22
22
|
# <%= render(Primer::LinkComponent.new(href: "#", muted: true)) { "Link" } %>
|
23
23
|
#
|
24
|
-
# @example
|
25
|
-
# <%= render(Primer::LinkComponent.new(href: "#",
|
26
|
-
# <%= render(Primer::LinkComponent.new(href: "#",
|
24
|
+
# @example Schemes
|
25
|
+
# <%= render(Primer::LinkComponent.new(href: "#", scheme: :primary)) { "Primary" } %>
|
26
|
+
# <%= render(Primer::LinkComponent.new(href: "#", scheme: :secondary)) { "Secondary" } %>
|
27
27
|
#
|
28
28
|
# @example Without underline
|
29
29
|
# <%= render(Primer::LinkComponent.new(href: "#", underline: false)) { "Link" } %>
|
@@ -33,17 +33,17 @@ module Primer
|
|
33
33
|
#
|
34
34
|
# @param tag [String] <%= one_of(Primer::LinkComponent::TAG_OPTIONS) %>
|
35
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
|
36
|
+
# @param scheme [Symbol] <%= one_of(Primer::LinkComponent::SCHEME_MAPPINGS.keys) %>
|
37
37
|
# @param muted [Boolean] Uses light gray for Link color, and blue on hover.
|
38
38
|
# @param underline [Boolean] Whether or not to underline the link.
|
39
39
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
40
|
-
def initialize(href: nil, tag: DEFAULT_TAG,
|
40
|
+
def initialize(href: nil, tag: DEFAULT_TAG, scheme: DEFAULT_SCHEME, muted: false, underline: true, **system_arguments)
|
41
41
|
@system_arguments = system_arguments
|
42
42
|
@system_arguments[:tag] = fetch_or_fallback(TAG_OPTIONS, tag, DEFAULT_TAG)
|
43
43
|
@system_arguments[:href] = href
|
44
44
|
@system_arguments[:classes] = class_names(
|
45
45
|
@system_arguments[:classes],
|
46
|
-
|
46
|
+
SCHEME_MAPPINGS[fetch_or_fallback(SCHEME_MAPPINGS.keys, scheme, DEFAULT_SCHEME)],
|
47
47
|
"Link" => tag == :span,
|
48
48
|
"Link--muted" => muted,
|
49
49
|
"no-underline" => !underline
|
@@ -3,8 +3,6 @@
|
|
3
3
|
module Primer
|
4
4
|
# Use menus to create vertical lists of navigational links.
|
5
5
|
class MenuComponent < Primer::Component
|
6
|
-
include ViewComponent::SlotableV2
|
7
|
-
|
8
6
|
# Optional menu heading
|
9
7
|
#
|
10
8
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
@@ -44,11 +42,11 @@ module Primer
|
|
44
42
|
# Item 1
|
45
43
|
# <% end %>
|
46
44
|
# <% c.item(href: "#url") do %>
|
47
|
-
# <%= render(Primer::OcticonComponent.new(
|
45
|
+
# <%= render(Primer::OcticonComponent.new("check")) %>
|
48
46
|
# With Icon
|
49
47
|
# <% end %>
|
50
48
|
# <% c.item(href: "#url") do %>
|
51
|
-
# <%= render(Primer::OcticonComponent.new(
|
49
|
+
# <%= render(Primer::OcticonComponent.new("check")) %>
|
52
50
|
# With Icon and Counter
|
53
51
|
# <%= render(Primer::CounterComponent.new(count: 25)) %>
|
54
52
|
# <% end %>
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Primer
|
4
|
+
module Navigation
|
5
|
+
# This component is part of navigation components such as `Primer::TabNavComponent`
|
6
|
+
# and `Primer::UnderlineNavComponent` and should not be used by itself.
|
7
|
+
class TabComponent < Primer::Component
|
8
|
+
# Panel controlled by the Tab. This will not render anything in the tab itself.
|
9
|
+
# It will provide a accessor for the Tab's parent to call and render the panel
|
10
|
+
# content in the appropriate place.
|
11
|
+
# Refer to `UnderlineNavComponent` and `TabNavComponent` implementations for examples.
|
12
|
+
#
|
13
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
14
|
+
renders_one :panel, lambda { |**system_arguments|
|
15
|
+
system_arguments[:tag] ||= :div
|
16
|
+
system_arguments[:role] ||= :tabpanel
|
17
|
+
system_arguments[:hidden] = true unless @selected
|
18
|
+
|
19
|
+
Primer::BaseComponent.new(**system_arguments)
|
20
|
+
}
|
21
|
+
|
22
|
+
# Icon to be rendered in the Tab left.
|
23
|
+
#
|
24
|
+
# @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::OcticonComponent) %>.
|
25
|
+
renders_one :icon, lambda { |icon = nil, **system_arguments|
|
26
|
+
system_arguments[:classes] = class_names(
|
27
|
+
@icon_classes,
|
28
|
+
system_arguments[:classes]
|
29
|
+
)
|
30
|
+
Primer::OcticonComponent.new(icon, **system_arguments)
|
31
|
+
}
|
32
|
+
|
33
|
+
# The Tab's text.
|
34
|
+
#
|
35
|
+
# @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::TextComponent) %>.
|
36
|
+
renders_one :text, Primer::TextComponent
|
37
|
+
|
38
|
+
# Counter to be rendered in the Tab right.
|
39
|
+
#
|
40
|
+
# @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::CounterComponent) %>.
|
41
|
+
renders_one :counter, Primer::CounterComponent
|
42
|
+
|
43
|
+
attr_reader :selected
|
44
|
+
|
45
|
+
# @example Default
|
46
|
+
# <%= render(Primer::Navigation::TabComponent.new(selected: true)) do |c| %>
|
47
|
+
# <% c.text { "Selected" } %>
|
48
|
+
# <% end %>
|
49
|
+
# <%= render(Primer::Navigation::TabComponent.new) do |c| %>
|
50
|
+
# <% c.text { "Not selected" } %>
|
51
|
+
# <% end %>
|
52
|
+
#
|
53
|
+
# @example With icons and counters
|
54
|
+
# <%= render(Primer::Navigation::TabComponent.new) do |c| %>
|
55
|
+
# <% c.icon(:star) %>
|
56
|
+
# <% c.text { "Tab" } %>
|
57
|
+
# <% end %>
|
58
|
+
# <%= render(Primer::Navigation::TabComponent.new) do |c| %>
|
59
|
+
# <% c.icon(:star) %>
|
60
|
+
# <% c.text { "Tab" } %>
|
61
|
+
# <% c.counter(count: 10) %>
|
62
|
+
# <% end %>
|
63
|
+
# <%= render(Primer::Navigation::TabComponent.new) do |c| %>
|
64
|
+
# <% c.text { "Tab" } %>
|
65
|
+
# <% c.counter(count: 10) %>
|
66
|
+
# <% end %>
|
67
|
+
#
|
68
|
+
# @example Inside a list
|
69
|
+
# <%= render(Primer::Navigation::TabComponent.new(list: true)) do |c| %>
|
70
|
+
# <% c.text { "Tab" } %>
|
71
|
+
# <% end %>
|
72
|
+
#
|
73
|
+
# @example With custom HTML
|
74
|
+
# <%= render(Primer::Navigation::TabComponent.new) do %>
|
75
|
+
# <div>
|
76
|
+
# This is my <strong>custom HTML</strong>
|
77
|
+
# </div>
|
78
|
+
# <% end %>
|
79
|
+
#
|
80
|
+
# @param list [Boolean] Whether the Tab is an item in a `<ul>` list.
|
81
|
+
# @param selected [Boolean] Whether the Tab is selected or not.
|
82
|
+
# @param with_panel [Boolean] Whether the Tab has an associated panel.
|
83
|
+
# @param icon_classes [Boolean] Classes that must always be applied to icons.
|
84
|
+
# @param wrapper_arguments [Hash] <%= link_to_system_arguments_docs %> to be used in the `<li>` wrapper when the tab is an item in a list.
|
85
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
86
|
+
def initialize(list: false, selected: false, with_panel: false, icon_classes: "", wrapper_arguments: {}, **system_arguments)
|
87
|
+
@selected = selected
|
88
|
+
@icon_classes = icon_classes
|
89
|
+
@list = list
|
90
|
+
|
91
|
+
@system_arguments = system_arguments
|
92
|
+
|
93
|
+
if with_panel
|
94
|
+
@system_arguments[:tag] ||= :button
|
95
|
+
@system_arguments[:type] = :button
|
96
|
+
@system_arguments[:role] = :tab
|
97
|
+
else
|
98
|
+
@system_arguments[:tag] ||= :a
|
99
|
+
end
|
100
|
+
|
101
|
+
@wrapper_arguments = wrapper_arguments
|
102
|
+
@wrapper_arguments[:tag] = :li
|
103
|
+
@wrapper_arguments[:display] ||= :flex
|
104
|
+
|
105
|
+
return unless @selected
|
106
|
+
|
107
|
+
if @system_arguments[:tag] == :a
|
108
|
+
@system_arguments[:"aria-current"] = :page
|
109
|
+
else
|
110
|
+
@system_arguments[:"aria-selected"] = true
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def wrapper
|
115
|
+
unless @list
|
116
|
+
yield
|
117
|
+
return # returning `yield` caused a double render
|
118
|
+
end
|
119
|
+
|
120
|
+
render(Primer::BaseComponent.new(**@wrapper_arguments)) do
|
121
|
+
yield
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -5,10 +5,6 @@ module Primer
|
|
5
5
|
class OcticonComponent < Primer::Component
|
6
6
|
status :beta
|
7
7
|
|
8
|
-
include ClassNameHelper
|
9
|
-
include TestSelectorHelper
|
10
|
-
include OcticonsHelper
|
11
|
-
|
12
8
|
SIZE_DEFAULT = :small
|
13
9
|
SIZE_MAPPINGS = {
|
14
10
|
SIZE_DEFAULT => 16,
|
@@ -18,19 +14,20 @@ module Primer
|
|
18
14
|
SIZE_OPTIONS = SIZE_MAPPINGS.keys
|
19
15
|
|
20
16
|
# @example Default
|
17
|
+
# <%= render(Primer::OcticonComponent.new("check")) %>
|
21
18
|
# <%= render(Primer::OcticonComponent.new(icon: "check")) %>
|
22
19
|
#
|
23
20
|
# @example Medium
|
24
|
-
# <%= render(Primer::OcticonComponent.new(
|
21
|
+
# <%= render(Primer::OcticonComponent.new("people", size: :medium)) %>
|
25
22
|
#
|
26
23
|
# @example Large
|
27
|
-
# <%= render(Primer::OcticonComponent.new(
|
24
|
+
# <%= render(Primer::OcticonComponent.new("x", size: :large)) %>
|
28
25
|
#
|
29
26
|
# @param icon [String] Name of [Octicon](https://primer.style/octicons/) to use.
|
30
27
|
# @param size [Symbol] <%= one_of(Primer::OcticonComponent::SIZE_MAPPINGS) %>
|
31
28
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
32
|
-
def initialize(icon
|
33
|
-
@icon = icon
|
29
|
+
def initialize(icon_name = nil, icon: nil, size: SIZE_DEFAULT, **system_arguments)
|
30
|
+
@icon = icon_name || icon
|
34
31
|
@system_arguments = system_arguments
|
35
32
|
|
36
33
|
@system_arguments[:class] = Primer::Classify.call(**@system_arguments)[:class]
|
@@ -5,7 +5,6 @@ module Primer
|
|
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
|
8
|
-
include ViewComponent::SlotableV2
|
9
8
|
status :beta
|
10
9
|
|
11
10
|
CARET_DEFAULT = :top
|
@@ -1,6 +1,4 @@
|
|
1
1
|
<%= render Primer::BaseComponent.new(**@system_arguments) do %>
|
2
2
|
<circle cx="8" cy="8" r="7" stroke="currentColor" stroke-opacity="0.25" stroke-width="2" vector-effect="non-scaling-stroke" />
|
3
|
-
<path d="M15 8a7.002 7.002 0 00-7-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" vector-effect="non-scaling-stroke"
|
4
|
-
<animateTransform attributeName="transform" type="rotate" from="0 8 8" to="360 8 8" dur="1s" repeatCount="indefinite" />
|
5
|
-
</path>
|
3
|
+
<path d="M15 8a7.002 7.002 0 00-7-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" vector-effect="non-scaling-stroke" />
|
6
4
|
<% end %>
|
@@ -31,6 +31,7 @@ module Primer
|
|
31
31
|
@system_arguments = system_arguments
|
32
32
|
@system_arguments[:tag] = :svg
|
33
33
|
@system_arguments[:style] ||= DEFAULT_STYLE
|
34
|
+
@system_arguments[:animation] = :rotate
|
34
35
|
@system_arguments[:width] = SIZE_MAPPINGS[fetch_or_fallback(SIZE_OPTIONS, size, DEFAULT_SIZE)]
|
35
36
|
@system_arguments[:height] = SIZE_MAPPINGS[fetch_or_fallback(SIZE_OPTIONS, size, DEFAULT_SIZE)]
|
36
37
|
@system_arguments[:viewBox] = "0 0 16 16"
|
@@ -5,21 +5,21 @@ module Primer
|
|
5
5
|
class StateComponent < Primer::Component
|
6
6
|
status :beta
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
SCHEME_DEFAULT = :default
|
9
|
+
NEW_SCHEME_MAPPINGS = {
|
10
10
|
open: "State--open",
|
11
11
|
closed: "State--closed",
|
12
12
|
merged: "State--merged"
|
13
13
|
}.freeze
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
DEPRECATED_SCHEME_MAPPINGS = {
|
16
|
+
SCHEME_DEFAULT => "",
|
17
17
|
:green => "State--open",
|
18
18
|
:red => "State--closed",
|
19
19
|
:purple => "State--merged"
|
20
20
|
}.freeze
|
21
|
-
|
22
|
-
|
21
|
+
SCHEME_MAPPINGS = NEW_SCHEME_MAPPINGS.merge(DEPRECATED_SCHEME_MAPPINGS)
|
22
|
+
SCHEME_OPTIONS = SCHEME_MAPPINGS.keys
|
23
23
|
|
24
24
|
SIZE_DEFAULT = :default
|
25
25
|
SIZE_MAPPINGS = {
|
@@ -34,24 +34,24 @@ module Primer
|
|
34
34
|
# @example Default
|
35
35
|
# <%= render(Primer::StateComponent.new(title: "title")) { "State" } %>
|
36
36
|
#
|
37
|
-
# @example
|
37
|
+
# @example Schemes
|
38
38
|
# <%= render(Primer::StateComponent.new(title: "title")) { "Default" } %>
|
39
|
-
# <%= render(Primer::StateComponent.new(title: "title",
|
40
|
-
# <%= render(Primer::StateComponent.new(title: "title",
|
41
|
-
# <%= render(Primer::StateComponent.new(title: "title",
|
39
|
+
# <%= render(Primer::StateComponent.new(title: "title", scheme: :open)) { "Open" } %>
|
40
|
+
# <%= render(Primer::StateComponent.new(title: "title", scheme: :closed)) { "Closed" } %>
|
41
|
+
# <%= render(Primer::StateComponent.new(title: "title", scheme: :merged)) { "Merged" } %>
|
42
42
|
#
|
43
43
|
# @example Sizes
|
44
44
|
# <%= render(Primer::StateComponent.new(title: "title")) { "Default" } %>
|
45
45
|
# <%= render(Primer::StateComponent.new(title: "title", size: :small)) { "Small" } %>
|
46
46
|
#
|
47
47
|
# @param title [String] `title` HTML attribute.
|
48
|
-
# @param
|
48
|
+
# @param scheme [Symbol] Background color. <%= one_of(Primer::StateComponent::SCHEME_OPTIONS) %>
|
49
49
|
# @param tag [Symbol] HTML tag for element. <%= one_of(Primer::StateComponent::TAG_OPTIONS) %>
|
50
50
|
# @param size [Symbol] <%= one_of(Primer::StateComponent::SIZE_OPTIONS) %>
|
51
51
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
52
52
|
def initialize(
|
53
53
|
title:,
|
54
|
-
|
54
|
+
scheme: SCHEME_DEFAULT,
|
55
55
|
tag: TAG_DEFAULT,
|
56
56
|
size: SIZE_DEFAULT,
|
57
57
|
**system_arguments
|
@@ -62,7 +62,7 @@ module Primer
|
|
62
62
|
@system_arguments[:classes] = class_names(
|
63
63
|
@system_arguments[:classes],
|
64
64
|
"State",
|
65
|
-
|
65
|
+
SCHEME_MAPPINGS[fetch_or_fallback(SCHEME_OPTIONS, scheme, SCHEME_DEFAULT)],
|
66
66
|
SIZE_MAPPINGS[fetch_or_fallback(SIZE_OPTIONS, size, SIZE_DEFAULT)]
|
67
67
|
)
|
68
68
|
end
|
@@ -5,8 +5,6 @@ module Primer
|
|
5
5
|
class SubheadComponent < Primer::Component
|
6
6
|
status :beta
|
7
7
|
|
8
|
-
include ViewComponent::SlotableV2
|
9
|
-
|
10
8
|
# The heading
|
11
9
|
#
|
12
10
|
# @param danger [Boolean] Whether to style the heading as dangerous.
|
@@ -73,7 +71,7 @@ module Primer
|
|
73
71
|
# <% component.actions do %>
|
74
72
|
# <%= render(
|
75
73
|
# Primer::ButtonComponent.new(
|
76
|
-
# tag: :a, href: "http://www.google.com",
|
74
|
+
# tag: :a, href: "http://www.google.com", scheme: :danger
|
77
75
|
# )
|
78
76
|
# ) { "Action" } %>
|
79
77
|
# <% end %>
|
@@ -1,17 +1,15 @@
|
|
1
|
-
<%=
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
<%= wrapper do %>
|
2
|
+
<%= render Primer::BaseComponent.new(**@system_arguments) do %>
|
3
|
+
<%= render Primer::BaseComponent.new(**@body_arguments) do %>
|
4
|
+
<% tabs.each do |tab| %>
|
5
|
+
<%= tab %>
|
6
|
+
<% end %>
|
5
7
|
<% end %>
|
6
|
-
|
8
|
+
<% end %>
|
7
9
|
|
8
10
|
<% if @with_panel %>
|
9
11
|
<% tabs.each do |tab| %>
|
10
|
-
|
11
|
-
<div role="tabpanel" <%= "hidden" if tab.hidden? %>>
|
12
|
-
<%= tab.panel %>
|
13
|
-
</div>
|
14
|
-
<% end %>
|
12
|
+
<%= tab.panel %>
|
15
13
|
<% end %>
|
16
14
|
<% end %>
|
17
15
|
<% end %>
|
@@ -3,106 +3,93 @@
|
|
3
3
|
module Primer
|
4
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
|
-
include
|
6
|
+
include Primer::TabbedComponentHelper
|
7
7
|
|
8
|
-
|
9
|
-
class NoSelectedTabsError < StandardError; end
|
10
|
-
|
11
|
-
# Tabs to be rendered.
|
8
|
+
# Tabs to be rendered. For more information, refer to <%= link_to_component(Primer::Navigation::TabComponent) %>.
|
12
9
|
#
|
13
|
-
# @param title [String] Text to be rendered by the tab.
|
14
10
|
# @param selected [Boolean] Whether the tab is selected.
|
15
11
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
16
|
-
renders_many :tabs, lambda {
|
17
|
-
|
12
|
+
renders_many :tabs, lambda { |selected: false, **system_arguments|
|
13
|
+
system_arguments[:classes] = class_names(
|
14
|
+
"tabnav-tab",
|
15
|
+
system_arguments[:classes]
|
16
|
+
)
|
18
17
|
|
19
|
-
TabComponent.new(
|
18
|
+
Primer::Navigation::TabComponent.new(
|
19
|
+
selected: selected,
|
20
|
+
with_panel: @with_panel,
|
21
|
+
**system_arguments
|
22
|
+
)
|
20
23
|
}
|
21
24
|
|
22
25
|
# @example Default
|
23
|
-
# <%= render(Primer::TabNavComponent.new) do |c| %>
|
24
|
-
# <% c.tab(selected: true,
|
25
|
-
# <% c.tab(
|
26
|
-
# <% c.tab(
|
26
|
+
# <%= render(Primer::TabNavComponent.new(label: "Default")) do |c| %>
|
27
|
+
# <% c.tab(selected: true, href: "#") { "Tab 1" }%>
|
28
|
+
# <% c.tab(href: "#") { "Tab 2" } %>
|
29
|
+
# <% c.tab(href: "#") { "Tab 3" } %>
|
30
|
+
# <% end %>
|
31
|
+
#
|
32
|
+
# @example With icons and counters
|
33
|
+
# <%= render(Primer::TabNavComponent.new(label: "With icons and counters")) do |component| %>
|
34
|
+
# <% component.tab(href: "#", selected: true) do |t| %>
|
35
|
+
# <% t.icon(icon: :star) %>
|
36
|
+
# <% t.text { "Item 1" } %>
|
37
|
+
# <% end %>
|
38
|
+
# <% component.tab(href: "#") do |t| %>
|
39
|
+
# <% t.icon(icon: :star) %>
|
40
|
+
# <% t.text { "Item 2" } %>
|
41
|
+
# <% t.counter(count: 10) %>
|
42
|
+
# <% end %>
|
43
|
+
# <% component.tab(href: "#") do |t| %>
|
44
|
+
# <% t.text { "Item 3" } %>
|
45
|
+
# <% t.counter(count: 10) %>
|
46
|
+
# <% end %>
|
27
47
|
# <% end %>
|
28
48
|
#
|
29
49
|
# @example With panels
|
30
|
-
# <%= render(Primer::TabNavComponent.new(with_panel: true)) do |c| %>
|
31
|
-
# <% c.tab(selected: true
|
32
|
-
#
|
33
|
-
#
|
50
|
+
# <%= render(Primer::TabNavComponent.new(label: "With panels", with_panel: true)) do |c| %>
|
51
|
+
# <% c.tab(selected: true) do |t| %>
|
52
|
+
# <% t.text { "Tab 1" } %>
|
53
|
+
# <% t.panel do %>
|
54
|
+
# Panel 1
|
55
|
+
# <% end %>
|
56
|
+
# <% end %>
|
57
|
+
# <% c.tab do |t| %>
|
58
|
+
# <% t.text { "Tab 2" } %>
|
59
|
+
# <% t.panel do %>
|
60
|
+
# Panel 2
|
61
|
+
# <% end %>
|
62
|
+
# <% end %>
|
63
|
+
# <% c.tab do |t| %>
|
64
|
+
# <% t.text { "Tab 3" } %>
|
65
|
+
# <% t.panel do %>
|
66
|
+
# Panel 3
|
67
|
+
# <% end %>
|
68
|
+
# <% end %>
|
34
69
|
# <% end %>
|
35
70
|
#
|
36
|
-
# @param
|
71
|
+
# @param label [String] Used to set the `aria-label` on the top level `<nav>` element.
|
37
72
|
# @param with_panel [Boolean] Whether the TabNav should navigate through pages or panels.
|
38
73
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
39
|
-
def initialize(
|
40
|
-
@aria_label = aria_label
|
74
|
+
def initialize(label:, with_panel: false, **system_arguments)
|
41
75
|
@with_panel = with_panel
|
42
76
|
@system_arguments = system_arguments
|
43
|
-
@system_arguments[:tag] ||= :div
|
44
77
|
|
78
|
+
@system_arguments[:tag] ||= :div
|
45
79
|
@system_arguments[:classes] = class_names(
|
46
80
|
"tabnav",
|
47
81
|
system_arguments[:classes]
|
48
82
|
)
|
49
|
-
end
|
50
|
-
|
51
|
-
def before_render
|
52
|
-
validate_single_selected_tab
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
def wrapper
|
58
|
-
@with_panel ? Primer::TabContainerComponent : Primer::BaseComponent
|
59
|
-
end
|
60
|
-
|
61
|
-
def validate_single_selected_tab
|
62
|
-
raise MultipleSelectedTabsError, "only one tab can be selected" if selected_tabs_count > 1
|
63
|
-
raise NoSelectedTabsError, "a tab must be selected" if selected_tabs_count != 1
|
64
|
-
end
|
65
|
-
|
66
|
-
def selected_tabs_count
|
67
|
-
@selected_tabs_count ||= tabs.count(&:selected)
|
68
|
-
end
|
69
|
-
|
70
|
-
# Tabs to be rendered.
|
71
|
-
class TabComponent < Primer::Component
|
72
|
-
attr_reader :selected
|
73
|
-
|
74
|
-
def initialize(title:, selected: false, **system_arguments)
|
75
|
-
@title = title
|
76
|
-
@selected = selected
|
77
|
-
@system_arguments = system_arguments
|
78
|
-
@system_arguments[:tag] ||= :a
|
79
|
-
@system_arguments[:role] = :tab
|
80
|
-
|
81
|
-
if selected
|
82
|
-
if @system_arguments[:tag] == :a
|
83
|
-
@system_arguments[:"aria-current"] = :page
|
84
|
-
else
|
85
|
-
@system_arguments[:"aria-selected"] = true
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
@system_arguments[:classes] = class_names(
|
90
|
-
"tabnav-tab",
|
91
|
-
system_arguments[:classes]
|
92
|
-
)
|
93
|
-
end
|
94
|
-
|
95
|
-
def call
|
96
|
-
render(Primer::BaseComponent.new(**@system_arguments)) { @title }
|
97
|
-
end
|
98
83
|
|
99
|
-
|
100
|
-
|
101
|
-
|
84
|
+
@body_arguments = {
|
85
|
+
tag: navigation_tag(with_panel),
|
86
|
+
classes: "tabnav-tabs",
|
87
|
+
aria: {
|
88
|
+
label: label
|
89
|
+
}
|
90
|
+
}
|
102
91
|
|
103
|
-
|
104
|
-
!@selected
|
105
|
-
end
|
92
|
+
@body_arguments[:role] = :tablist if @with_panel
|
106
93
|
end
|
107
94
|
end
|
108
95
|
end
|