primer_view_components 0.0.31 → 0.0.32
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 +18 -0
- data/README.md +1 -1
- data/app/components/primer/auto_complete_component.rb +0 -2
- data/app/components/primer/auto_complete_item_component.rb +0 -2
- data/app/components/primer/avatar_stack_component.rb +0 -2
- 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_group_component.rb +0 -2
- data/app/components/primer/component.rb +2 -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 +0 -2
- data/app/components/primer/flash_component.html.erb +2 -2
- data/app/components/primer/flash_component.rb +0 -2
- data/app/components/primer/layout_component.rb +0 -2
- data/app/components/primer/menu_component.rb +2 -4
- data/app/components/primer/navigation/tab_component.html.erb +9 -0
- data/app/components/primer/navigation/tab_component.rb +102 -0
- data/app/components/primer/octicon_component.rb +5 -4
- data/app/components/primer/popover_component.rb +0 -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/subhead_component.rb +0 -2
- data/app/components/primer/tab_nav_component.html.erb +9 -11
- data/app/components/primer/tab_nav_component.rb +46 -73
- data/app/components/primer/time_ago_component.rb +2 -1
- data/app/components/primer/timeline_item_component.rb +1 -2
- data/app/components/primer/underline_nav_component.html.erb +19 -7
- data/app/components/primer/underline_nav_component.rb +80 -14
- data/app/lib/primer/classify.rb +2 -2
- data/app/lib/primer/tabbed_component_helper.rb +37 -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 +5 -3
- data/app/components/primer/slot.rb +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b994be67e7454dab595ebdf8745db530f855ef34a9ce292e6b8110ae4f2cf060
|
4
|
+
data.tar.gz: 33c5ee3a0e757c39434451c2c86ff32586add5f06636e4dfb6f89a52ac89cd59
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3f526574142849b3312b6029688b59532faa4e7f82e6377128eadbcfeec78decba9ed2aa514a452029afe6946102114338d681348e91eedb681a3a964e1c8463
|
7
|
+
data.tar.gz: 20b4c8a3541de434cdebf3b40c1e07e610dc366a456f937003a05c31f0f9a074090337849fcf4c72cccbca06641ab3705952805c13f211013abe8549e58645bb
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,24 @@
|
|
2
2
|
|
3
3
|
## main
|
4
4
|
|
5
|
+
## 0.0.32
|
6
|
+
|
7
|
+
* Allow passing the icon name as a positional argument to `OcticonComponent`.
|
8
|
+
|
9
|
+
*Manuel Puyol*
|
10
|
+
|
11
|
+
* Promote `TimeAgoComponent` to beta.
|
12
|
+
|
13
|
+
*Manuel Puyol*
|
14
|
+
|
15
|
+
* **Breaking change**: Update `TabNav#tab` API to accept the tab content as a block and panel content as a slot.
|
16
|
+
|
17
|
+
*Manuel Puyol*
|
18
|
+
|
19
|
+
* **Breaking change**: Update `UnderlineNavComponent` API be more strict and support `TabContainer`.
|
20
|
+
|
21
|
+
*Manuel Puyol*
|
22
|
+
|
5
23
|
## 0.0.31
|
6
24
|
|
7
25
|
* Fix `Popover` bug where body was only returning the last line of the HTML.
|
data/README.md
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
|
7
7
|
<p align="center">ViewComponents for the Primer Design System</p>
|
8
8
|
|
9
|
-
_Note: This library is
|
9
|
+
_Note: This library is under active pre-1.0 development. Breaking changes are likely in patch releases._
|
10
10
|
|
11
11
|
## Documentation
|
12
12
|
|
@@ -3,8 +3,6 @@
|
|
3
3
|
module Primer
|
4
4
|
# Use AutoComplete to populate input values from server search results.
|
5
5
|
class AutoCompleteComponent < Primer::Component
|
6
|
-
include ViewComponent::SlotableV2
|
7
|
-
|
8
6
|
DEFAULT_INPUT_TYPE = :text
|
9
7
|
INPUT_TYPE_OPTIONS = [DEFAULT_INPUT_TYPE, :search].freeze
|
10
8
|
|
@@ -3,8 +3,6 @@
|
|
3
3
|
module Primer
|
4
4
|
# Use AutoCompleteItem to list results of an auto-completed search.
|
5
5
|
class AutoCompleteItemComponent < Primer::Component
|
6
|
-
include ViewComponent::SlotableV2
|
7
|
-
|
8
6
|
# @example Default
|
9
7
|
# <%= render(Primer::AutoCompleteItemComponent.new(selected: true, value: "value")) do |c| %>
|
10
8
|
# Selected
|
@@ -2,7 +2,7 @@
|
|
2
2
|
<% if spinner.present? %>
|
3
3
|
<%= spinner %>
|
4
4
|
<% elsif @icon.present? %>
|
5
|
-
<%= primer_octicon
|
5
|
+
<%= primer_octicon @icon, size: @icon_size, classes: "blankslate-icon" %>
|
6
6
|
<% elsif @image_src.present? && @image_alt.present? %>
|
7
7
|
<%= image_tag "#{@image_src}", class: "mb-3", size: "56x56", alt: "#{@image_alt}" %>
|
8
8
|
<% end %>
|
@@ -3,7 +3,6 @@
|
|
3
3
|
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
|
-
include ViewComponent::SlotableV2
|
7
6
|
status :beta
|
8
7
|
|
9
8
|
# _Note: if both `href` and `selected: true` are passed in, `href` will be ignored and the item will not be rendered as a link._
|
@@ -3,8 +3,6 @@
|
|
3
3
|
module Primer
|
4
4
|
# Use ButtonGroupComponent to render a series of buttons.
|
5
5
|
class ButtonGroupComponent < Primer::Component
|
6
|
-
include ViewComponent::SlotableV2
|
7
|
-
|
8
6
|
# Required list of buttons to be rendered.
|
9
7
|
#
|
10
8
|
# @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::ButtonComponent) %>.
|
@@ -1,10 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "octicons_helper/helper"
|
4
|
+
require "view_component/version"
|
4
5
|
|
5
6
|
module Primer
|
6
7
|
# @private
|
7
8
|
class Component < ViewComponent::Base
|
9
|
+
include ViewComponent::SlotableV2 unless ViewComponent::VERSION::STRING.to_f >= 2.28
|
8
10
|
include ClassNameHelper
|
9
11
|
include FetchOrFallbackHelper
|
10
12
|
include OcticonsHelper
|
@@ -5,8 +5,6 @@ module Primer
|
|
5
5
|
# This component is part of `Primer::DropdownComponent` and should not be
|
6
6
|
# used as a standalone component.
|
7
7
|
class MenuComponent < Primer::Component
|
8
|
-
include ViewComponent::SlotableV2
|
9
|
-
|
10
8
|
SCHEME_DEFAULT = :default
|
11
9
|
SCHEME_MAPPINGS = {
|
12
10
|
SCHEME_DEFAULT => "",
|
@@ -4,8 +4,6 @@ module Primer
|
|
4
4
|
# Dropdowns are lightweight context menus for housing navigation and actions.
|
5
5
|
# They're great for instances where you don't need the full power (and code) of the select menu.
|
6
6
|
class DropdownComponent < Primer::Component
|
7
|
-
include ViewComponent::SlotableV2
|
8
|
-
|
9
7
|
# Required trigger for the dropdown. Only accepts a content.
|
10
8
|
# Its classes can be customized by the `summary_classes` param in the parent component
|
11
9
|
renders_one :button
|
@@ -1,9 +1,9 @@
|
|
1
1
|
<%= render Primer::BaseComponent.new(**@system_arguments) do %>
|
2
|
-
<%= primer_octicon
|
2
|
+
<%= primer_octicon @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
|
6
|
+
<%= primer_octicon "x" %>
|
7
7
|
</button>
|
8
8
|
<% end %>
|
9
9
|
|
@@ -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,102 @@
|
|
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 With custom HTML
|
69
|
+
# <%= render(Primer::Navigation::TabComponent.new) do |c| %>
|
70
|
+
# <div>
|
71
|
+
# This is my <strong>custom HTML</strong>
|
72
|
+
# </div>
|
73
|
+
# <% end %>
|
74
|
+
#
|
75
|
+
# @param selected [Boolean] Whether the Tab is selected or not.
|
76
|
+
# @param with_panel [Boolean] Whether the Tab has an associated panel.
|
77
|
+
# @param icon_classes [Boolean] Classes that must always be applied to icons.
|
78
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
79
|
+
def initialize(selected: false, with_panel: false, icon_classes: "", **system_arguments)
|
80
|
+
@selected = selected
|
81
|
+
@icon_classes = icon_classes
|
82
|
+
@system_arguments = system_arguments
|
83
|
+
@system_arguments[:role] = :tab
|
84
|
+
|
85
|
+
if with_panel
|
86
|
+
@system_arguments[:tag] ||= :button
|
87
|
+
@system_arguments[:type] = :button
|
88
|
+
else
|
89
|
+
@system_arguments[:tag] ||= :a
|
90
|
+
end
|
91
|
+
|
92
|
+
return unless @selected
|
93
|
+
|
94
|
+
if @system_arguments[:tag] == :a
|
95
|
+
@system_arguments[:"aria-current"] = :page
|
96
|
+
else
|
97
|
+
@system_arguments[:"aria-selected"] = true
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -18,19 +18,20 @@ module Primer
|
|
18
18
|
SIZE_OPTIONS = SIZE_MAPPINGS.keys
|
19
19
|
|
20
20
|
# @example Default
|
21
|
+
# <%= render(Primer::OcticonComponent.new("check")) %>
|
21
22
|
# <%= render(Primer::OcticonComponent.new(icon: "check")) %>
|
22
23
|
#
|
23
24
|
# @example Medium
|
24
|
-
# <%= render(Primer::OcticonComponent.new(
|
25
|
+
# <%= render(Primer::OcticonComponent.new("people", size: :medium)) %>
|
25
26
|
#
|
26
27
|
# @example Large
|
27
|
-
# <%= render(Primer::OcticonComponent.new(
|
28
|
+
# <%= render(Primer::OcticonComponent.new("x", size: :large)) %>
|
28
29
|
#
|
29
30
|
# @param icon [String] Name of [Octicon](https://primer.style/octicons/) to use.
|
30
31
|
# @param size [Symbol] <%= one_of(Primer::OcticonComponent::SIZE_MAPPINGS) %>
|
31
32
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
32
|
-
def initialize(icon
|
33
|
-
@icon = icon
|
33
|
+
def initialize(icon_name = nil, icon: nil, size: SIZE_DEFAULT, **system_arguments)
|
34
|
+
@icon = icon_name || icon
|
34
35
|
@system_arguments = system_arguments
|
35
36
|
|
36
37
|
@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"
|
@@ -1,17 +1,15 @@
|
|
1
|
-
<%=
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
<%= wrapper do %>
|
2
|
+
<%= render Primer::BaseComponent.new(**@system_arguments) do %>
|
3
|
+
<nav role="tablist" aria-label="<%= @aria_label %>" class="tabnav-tabs">
|
4
|
+
<% tabs.each do |tab| %>
|
5
|
+
<%= tab %>
|
6
|
+
<% end %>
|
7
|
+
</nav>
|
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,34 +3,64 @@
|
|
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
|
-
|
18
|
-
|
19
|
-
|
12
|
+
renders_many :tabs, lambda { |selected: false, **system_arguments|
|
13
|
+
system_arguments[:classes] = class_names(
|
14
|
+
"tabnav-tab",
|
15
|
+
system_arguments[:classes]
|
16
|
+
)
|
17
|
+
Primer::Navigation::TabComponent.new(selected: selected, with_panel: @with_panel, **system_arguments)
|
20
18
|
}
|
21
19
|
|
22
20
|
# @example Default
|
23
21
|
# <%= render(Primer::TabNavComponent.new) do |c| %>
|
24
|
-
# <% c.tab(selected: true,
|
25
|
-
# <% c.tab(
|
26
|
-
# <% c.tab(
|
22
|
+
# <% c.tab(selected: true, href: "#") { "Tab 1" }%>
|
23
|
+
# <% c.tab(href: "#") { "Tab 2" } %>
|
24
|
+
# <% c.tab(href: "#") { "Tab 3" } %>
|
25
|
+
# <% end %>
|
26
|
+
#
|
27
|
+
# @example With icons and counters
|
28
|
+
# <%= render(Primer::TabNavComponent.new) do |component| %>
|
29
|
+
# <% component.tab(href: "#", selected: true) do |t| %>
|
30
|
+
# <% t.icon(icon: :star) %>
|
31
|
+
# <% t.text { "Item 1" } %>
|
32
|
+
# <% end %>
|
33
|
+
# <% component.tab(href: "#") do |t| %>
|
34
|
+
# <% t.icon(icon: :star) %>
|
35
|
+
# <% t.text { "Item 2" } %>
|
36
|
+
# <% t.counter(count: 10) %>
|
37
|
+
# <% end %>
|
38
|
+
# <% component.tab(href: "#") do |t| %>
|
39
|
+
# <% t.text { "Item 3" } %>
|
40
|
+
# <% t.counter(count: 10) %>
|
41
|
+
# <% end %>
|
27
42
|
# <% end %>
|
28
43
|
#
|
29
44
|
# @example With panels
|
30
45
|
# <%= render(Primer::TabNavComponent.new(with_panel: true)) do |c| %>
|
31
|
-
# <% c.tab(selected: true
|
32
|
-
#
|
33
|
-
#
|
46
|
+
# <% c.tab(selected: true) do |t| %>
|
47
|
+
# <% t.text { "Tab 1" } %>
|
48
|
+
# <% t.panel do %>
|
49
|
+
# Panel 1
|
50
|
+
# <% end %>
|
51
|
+
# <% end %>
|
52
|
+
# <% c.tab do |t| %>
|
53
|
+
# <% t.text { "Tab 2" } %>
|
54
|
+
# <% t.panel do %>
|
55
|
+
# Panel 2
|
56
|
+
# <% end %>
|
57
|
+
# <% end %>
|
58
|
+
# <% c.tab do |t| %>
|
59
|
+
# <% t.text { "Tab 3" } %>
|
60
|
+
# <% t.panel do %>
|
61
|
+
# Panel 3
|
62
|
+
# <% end %>
|
63
|
+
# <% end %>
|
34
64
|
# <% end %>
|
35
65
|
#
|
36
66
|
# @param aria_label [String] Used to set the `aria-label` on the top level `<nav>` element.
|
@@ -47,62 +77,5 @@ module Primer
|
|
47
77
|
system_arguments[:classes]
|
48
78
|
)
|
49
79
|
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
|
-
|
99
|
-
def panel
|
100
|
-
content
|
101
|
-
end
|
102
|
-
|
103
|
-
def hidden?
|
104
|
-
!@selected
|
105
|
-
end
|
106
|
-
end
|
107
80
|
end
|
108
81
|
end
|
@@ -3,7 +3,8 @@
|
|
3
3
|
module Primer
|
4
4
|
# Use Primer::TimeAgoComponent 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
8
|
# @example Default
|
8
9
|
# <%= render(Primer::TimeAgoComponent.new(time: Time.at(628232400))) %>
|
9
10
|
#
|
@@ -3,7 +3,6 @@
|
|
3
3
|
module Primer
|
4
4
|
# Use `TimelineItem` to display items on a vertical timeline, connected by badge elements.
|
5
5
|
class TimelineItemComponent < Primer::Component
|
6
|
-
include ViewComponent::SlotableV2
|
7
6
|
status :beta
|
8
7
|
|
9
8
|
# Avatar to be rendered to the left of the Badge.
|
@@ -78,7 +77,7 @@ module Primer
|
|
78
77
|
|
79
78
|
def call
|
80
79
|
render(Primer::BaseComponent.new(**@system_arguments)) do
|
81
|
-
render(Primer::OcticonComponent.new(
|
80
|
+
render(Primer::OcticonComponent.new(@icon))
|
82
81
|
end
|
83
82
|
end
|
84
83
|
end
|
@@ -1,11 +1,23 @@
|
|
1
|
-
<%=
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
<%= wrapper do %>
|
2
|
+
<%= render Primer::BaseComponent.new(**@system_arguments) do %>
|
3
|
+
<% if @align == :right %>
|
4
|
+
<%= actions %>
|
5
|
+
<% end %>
|
6
|
+
|
7
|
+
<%= render body do %>
|
8
|
+
<% tabs.each do |tab| %>
|
9
|
+
<%= tab %>
|
10
|
+
<% end %>
|
11
|
+
<% end %>
|
5
12
|
|
6
|
-
|
13
|
+
<% if @align == :left %>
|
14
|
+
<%= actions %>
|
15
|
+
<% end %>
|
16
|
+
<% end %>
|
7
17
|
|
8
|
-
<% if @
|
9
|
-
|
18
|
+
<% if @with_panel %>
|
19
|
+
<% tabs.each do |tab| %>
|
20
|
+
<%= tab.panel %>
|
21
|
+
<% end %>
|
10
22
|
<% end %>
|
11
23
|
<% end %>
|
@@ -5,34 +5,61 @@ module Primer
|
|
5
5
|
# underlined selected state, typically used for navigation placed at the top
|
6
6
|
# of the page.
|
7
7
|
class UnderlineNavComponent < Primer::Component
|
8
|
-
include
|
8
|
+
include Primer::TabbedComponentHelper
|
9
9
|
|
10
10
|
ALIGN_DEFAULT = :left
|
11
11
|
ALIGN_OPTIONS = [ALIGN_DEFAULT, :right].freeze
|
12
12
|
|
13
|
-
#
|
13
|
+
# Use the tabs to list navigation items. For more information, refer to <%= link_to_component(Primer::Navigation::TabComponent) %>.
|
14
14
|
#
|
15
|
+
# @param selected [Boolean] Whether the tab is selected.
|
15
16
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
16
|
-
|
17
|
-
system_arguments[:classes] = class_names(
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
renders_many :tabs, lambda { |selected: false, **system_arguments|
|
18
|
+
system_arguments[:classes] = class_names(
|
19
|
+
"UnderlineNav-item",
|
20
|
+
system_arguments[:classes]
|
21
|
+
)
|
22
|
+
Primer::Navigation::TabComponent.new(
|
23
|
+
selected: selected,
|
24
|
+
with_panel: @with_panel,
|
25
|
+
icon_classes: "UnderlineNav-octicon",
|
26
|
+
**system_arguments
|
27
|
+
)
|
21
28
|
}
|
22
29
|
|
23
|
-
#
|
30
|
+
# Use actions for a call to action.
|
24
31
|
#
|
25
32
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
26
33
|
renders_one :actions, lambda { |**system_arguments|
|
27
34
|
system_arguments[:tag] ||= :div
|
28
35
|
system_arguments[:classes] = class_names("UnderlineNav-actions", system_arguments[:classes])
|
29
|
-
|
36
|
+
|
37
|
+
Primer::BaseComponent.new(**system_arguments)
|
30
38
|
}
|
31
39
|
|
32
40
|
# @example Default
|
33
41
|
# <%= render(Primer::UnderlineNavComponent.new) do |component| %>
|
34
|
-
# <% component.
|
35
|
-
#
|
42
|
+
# <% component.tab(href: "#", selected: true) { "Item 1" } %>
|
43
|
+
# <% component.tab(href: "#") { "Item 2" } %>
|
44
|
+
# <% component.actions do %>
|
45
|
+
# <%= render(Primer::ButtonComponent.new) { "Button!" } %>
|
46
|
+
# <% end %>
|
47
|
+
# <% end %>
|
48
|
+
#
|
49
|
+
# @example With icons and counters
|
50
|
+
# <%= render(Primer::UnderlineNavComponent.new) do |component| %>
|
51
|
+
# <% component.tab(href: "#", selected: true) do |t| %>
|
52
|
+
# <% t.icon(icon: :star) %>
|
53
|
+
# <% t.text { "Item 1" } %>
|
54
|
+
# <% end %>
|
55
|
+
# <% component.tab(href: "#") do |t| %>
|
56
|
+
# <% t.icon(icon: :star) %>
|
57
|
+
# <% t.text { "Item 2" } %>
|
58
|
+
# <% t.counter(count: 10) %>
|
59
|
+
# <% end %>
|
60
|
+
# <% component.tab(href: "#") do |t| %>
|
61
|
+
# <% t.text { "Item 3" } %>
|
62
|
+
# <% t.counter(count: 10) %>
|
36
63
|
# <% end %>
|
37
64
|
# <% component.actions do %>
|
38
65
|
# <%= render(Primer::ButtonComponent.new) { "Button!" } %>
|
@@ -41,26 +68,65 @@ module Primer
|
|
41
68
|
#
|
42
69
|
# @example Align right
|
43
70
|
# <%= render(Primer::UnderlineNavComponent.new(align: :right)) do |component| %>
|
44
|
-
# <% component.
|
45
|
-
#
|
71
|
+
# <% component.tab(href: "#", selected: true) do |t| %>
|
72
|
+
# <% t.text { "Item 1" } %>
|
73
|
+
# <% end %>
|
74
|
+
# <% component.tab(href: "#") do |t| %>
|
75
|
+
# <% t.text { "Item 2" } %>
|
76
|
+
# <% end %>
|
77
|
+
# <% component.actions do %>
|
78
|
+
# <%= render(Primer::ButtonComponent.new) { "Button!" } %>
|
79
|
+
# <% end %>
|
80
|
+
# <% end %>
|
81
|
+
#
|
82
|
+
# @example With panels
|
83
|
+
# <%= render(Primer::UnderlineNavComponent.new(with_panel: true)) do |component| %>
|
84
|
+
# <% component.tab(selected: true) do |t| %>
|
85
|
+
# <% t.text { "Item 1" } %>
|
86
|
+
# <% t.panel do %>
|
87
|
+
# Panel 1
|
88
|
+
# <% end %>
|
89
|
+
# <% end %>
|
90
|
+
# <% component.tab do |t| %>
|
91
|
+
# <% t.text { "Item 2" } %>
|
92
|
+
# <% t.panel do %>
|
93
|
+
# Panel 2
|
94
|
+
# <% end %>
|
46
95
|
# <% end %>
|
47
96
|
# <% component.actions do %>
|
48
97
|
# <%= render(Primer::ButtonComponent.new) { "Button!" } %>
|
49
98
|
# <% end %>
|
50
99
|
# <% end %>
|
51
100
|
#
|
101
|
+
# @param with_panel [Boolean] Whether the TabNav should navigate through pages or panels.
|
52
102
|
# @param align [Symbol] <%= one_of(Primer::UnderlineNavComponent::ALIGN_OPTIONS) %> - Defaults to <%= Primer::UnderlineNavComponent::ALIGN_DEFAULT %>
|
53
103
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
54
|
-
def initialize(align: ALIGN_DEFAULT, **system_arguments)
|
104
|
+
def initialize(with_panel: false, align: ALIGN_DEFAULT, body_classes: "", **system_arguments)
|
105
|
+
@with_panel = with_panel
|
55
106
|
@align = fetch_or_fallback(ALIGN_OPTIONS, align, ALIGN_DEFAULT)
|
56
107
|
|
57
108
|
@system_arguments = system_arguments
|
58
109
|
@system_arguments[:tag] = :nav
|
110
|
+
@system_arguments[:role] = :tablist
|
59
111
|
@system_arguments[:classes] = class_names(
|
60
112
|
@system_arguments[:classes],
|
61
113
|
"UnderlineNav",
|
62
114
|
"UnderlineNav--right" => @align == :right
|
63
115
|
)
|
116
|
+
|
117
|
+
@body_arguments = {
|
118
|
+
tag: :div,
|
119
|
+
classes: class_names(
|
120
|
+
"UnderlineNav-body",
|
121
|
+
body_classes
|
122
|
+
)
|
123
|
+
}
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def body
|
129
|
+
Primer::BaseComponent.new(**@body_arguments)
|
64
130
|
end
|
65
131
|
end
|
66
132
|
end
|
data/app/lib/primer/classify.rb
CHANGED
@@ -192,8 +192,8 @@ module Primer
|
|
192
192
|
end
|
193
193
|
|
194
194
|
if BOOLEAN_MAPPINGS.key?(key)
|
195
|
-
BOOLEAN_MAPPINGS[key][:mappings].
|
196
|
-
memo[:classes] << css_class
|
195
|
+
BOOLEAN_MAPPINGS[key][:mappings].each do |m|
|
196
|
+
memo[:classes] << m[:css_class] if m[:value] == val && m[:css_class].present?
|
197
197
|
end
|
198
198
|
elsif key == BG_KEY
|
199
199
|
if val.to_s.start_with?("#")
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/concern"
|
4
|
+
|
5
|
+
module Primer
|
6
|
+
# Helper to share tab validation logic between components.
|
7
|
+
# The component will raise an error if there are 0 or 2+ selected tabs.
|
8
|
+
module TabbedComponentHelper
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
class MultipleSelectedTabsError < StandardError; end
|
12
|
+
class NoSelectedTabsError < StandardError; end
|
13
|
+
|
14
|
+
def before_render
|
15
|
+
validate_single_selected_tab unless Rails.env.production?
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def wrapper
|
21
|
+
return yield unless @with_panel
|
22
|
+
|
23
|
+
render Primer::TabContainerComponent.new do
|
24
|
+
yield
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def validate_single_selected_tab
|
29
|
+
raise MultipleSelectedTabsError, "only one tab can be selected" if selected_tabs_count > 1
|
30
|
+
raise NoSelectedTabsError, "a tab must be selected" if selected_tabs_count != 1
|
31
|
+
end
|
32
|
+
|
33
|
+
def selected_tabs_count
|
34
|
+
@selected_tabs_count ||= tabs.count(&:selected)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -12,8 +12,8 @@ module Primer
|
|
12
12
|
}.freeze
|
13
13
|
|
14
14
|
HELPERS.each do |name, component|
|
15
|
-
define_method "primer_#{name}" do
|
16
|
-
render component.constantize.new(**
|
15
|
+
define_method "primer_#{name}" do |*args, **kwargs, &block|
|
16
|
+
render component.constantize.new(*args, **kwargs), &block
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
data/static/statuses.json
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"Primer::AutoCompleteComponent":"alpha","Primer::AutoCompleteItemComponent":"alpha","Primer::AvatarComponent":"beta","Primer::AvatarStackComponent":"alpha","Primer::BaseComponent":"beta","Primer::BlankslateComponent":"beta","Primer::BorderBoxComponent":"beta","Primer::BoxComponent":"stable","Primer::BreadcrumbComponent":"beta","Primer::BreadcrumbComponent::ItemComponent":"alpha","Primer::ButtonComponent":"alpha","Primer::ButtonGroupComponent":"alpha","Primer::ButtonMarketingComponent":"alpha","Primer::CounterComponent":"beta","Primer::DetailsComponent":"beta","Primer::Dropdown::MenuComponent":"alpha","Primer::DropdownComponent":"alpha","Primer::DropdownMenuComponent":"deprecated","Primer::FlashComponent":"beta","Primer::FlexComponent":"alpha","Primer::FlexItemComponent":"alpha","Primer::HeadingComponent":"beta","Primer::LabelComponent":"beta","Primer::LayoutComponent":"alpha","Primer::LinkComponent":"beta","Primer::MarkdownComponent":"alpha","Primer::MenuComponent":"alpha","Primer::OcticonComponent":"beta","Primer::PopoverComponent":"beta","Primer::ProgressBarComponent":"beta","Primer::SpinnerComponent":"beta","Primer::StateComponent":"beta","Primer::SubheadComponent":"beta","Primer::TabContainerComponent":"alpha","Primer::TabNavComponent":"alpha","Primer::
|
1
|
+
{"Primer::AutoCompleteComponent":"alpha","Primer::AutoCompleteItemComponent":"alpha","Primer::AvatarComponent":"beta","Primer::AvatarStackComponent":"alpha","Primer::BaseComponent":"beta","Primer::BlankslateComponent":"beta","Primer::BorderBoxComponent":"beta","Primer::BoxComponent":"stable","Primer::BreadcrumbComponent":"beta","Primer::BreadcrumbComponent::ItemComponent":"alpha","Primer::ButtonComponent":"alpha","Primer::ButtonGroupComponent":"alpha","Primer::ButtonMarketingComponent":"alpha","Primer::CounterComponent":"beta","Primer::DetailsComponent":"beta","Primer::Dropdown::MenuComponent":"alpha","Primer::DropdownComponent":"alpha","Primer::DropdownMenuComponent":"deprecated","Primer::FlashComponent":"beta","Primer::FlexComponent":"alpha","Primer::FlexItemComponent":"alpha","Primer::HeadingComponent":"beta","Primer::LabelComponent":"beta","Primer::LayoutComponent":"alpha","Primer::LinkComponent":"beta","Primer::MarkdownComponent":"alpha","Primer::MenuComponent":"alpha","Primer::Navigation::TabComponent":"alpha","Primer::OcticonComponent":"beta","Primer::PopoverComponent":"beta","Primer::ProgressBarComponent":"beta","Primer::SpinnerComponent":"beta","Primer::StateComponent":"beta","Primer::SubheadComponent":"beta","Primer::TabContainerComponent":"alpha","Primer::TabNavComponent":"alpha","Primer::TextComponent":"beta","Primer::TimeAgoComponent":"beta","Primer::TimelineItemComponent":"beta","Primer::TimelineItemComponent::BadgeComponent":"alpha","Primer::TooltipComponent":"alpha","Primer::TruncateComponent":"alpha","Primer::UnderlineNavComponent":"alpha"}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: primer_view_components
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.32
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GitHub Open Source
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-03-
|
11
|
+
date: 2021-03-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: octicons_helper
|
@@ -295,6 +295,8 @@ files:
|
|
295
295
|
- app/components/primer/markdown_component.rb
|
296
296
|
- app/components/primer/menu_component.html.erb
|
297
297
|
- app/components/primer/menu_component.rb
|
298
|
+
- app/components/primer/navigation/tab_component.html.erb
|
299
|
+
- app/components/primer/navigation/tab_component.rb
|
298
300
|
- app/components/primer/octicon_component.rb
|
299
301
|
- app/components/primer/popover_component.html.erb
|
300
302
|
- app/components/primer/popover_component.rb
|
@@ -303,7 +305,6 @@ files:
|
|
303
305
|
- app/components/primer/primer.ts
|
304
306
|
- app/components/primer/progress_bar_component.html.erb
|
305
307
|
- app/components/primer/progress_bar_component.rb
|
306
|
-
- app/components/primer/slot.rb
|
307
308
|
- app/components/primer/spinner_component.html.erb
|
308
309
|
- app/components/primer/spinner_component.rb
|
309
310
|
- app/components/primer/state_component.rb
|
@@ -336,6 +337,7 @@ files:
|
|
336
337
|
- app/lib/primer/fetch_or_fallback_helper.rb
|
337
338
|
- app/lib/primer/join_style_arguments_helper.rb
|
338
339
|
- app/lib/primer/status/dsl.rb
|
340
|
+
- app/lib/primer/tabbed_component_helper.rb
|
339
341
|
- app/lib/primer/test_selector_helper.rb
|
340
342
|
- app/lib/primer/view_helper.rb
|
341
343
|
- lib/primer/view_components.rb
|