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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -0
  3. data/README.md +1 -1
  4. data/app/components/primer/auto_complete_component.rb +0 -2
  5. data/app/components/primer/auto_complete_item_component.rb +0 -2
  6. data/app/components/primer/avatar_stack_component.rb +0 -2
  7. data/app/components/primer/blankslate_component.html.erb +1 -1
  8. data/app/components/primer/blankslate_component.rb +0 -2
  9. data/app/components/primer/border_box_component.rb +0 -2
  10. data/app/components/primer/breadcrumb_component.rb +0 -1
  11. data/app/components/primer/button_group_component.rb +0 -2
  12. data/app/components/primer/component.rb +2 -0
  13. data/app/components/primer/details_component.rb +0 -1
  14. data/app/components/primer/dropdown/menu_component.rb +0 -2
  15. data/app/components/primer/dropdown_component.rb +0 -2
  16. data/app/components/primer/flash_component.html.erb +2 -2
  17. data/app/components/primer/flash_component.rb +0 -2
  18. data/app/components/primer/layout_component.rb +0 -2
  19. data/app/components/primer/menu_component.rb +2 -4
  20. data/app/components/primer/navigation/tab_component.html.erb +9 -0
  21. data/app/components/primer/navigation/tab_component.rb +102 -0
  22. data/app/components/primer/octicon_component.rb +5 -4
  23. data/app/components/primer/popover_component.rb +0 -1
  24. data/app/components/primer/progress_bar_component.rb +0 -1
  25. data/app/components/primer/spinner_component.html.erb +1 -3
  26. data/app/components/primer/spinner_component.rb +1 -0
  27. data/app/components/primer/subhead_component.rb +0 -2
  28. data/app/components/primer/tab_nav_component.html.erb +9 -11
  29. data/app/components/primer/tab_nav_component.rb +46 -73
  30. data/app/components/primer/time_ago_component.rb +2 -1
  31. data/app/components/primer/timeline_item_component.rb +1 -2
  32. data/app/components/primer/underline_nav_component.html.erb +19 -7
  33. data/app/components/primer/underline_nav_component.rb +80 -14
  34. data/app/lib/primer/classify.rb +2 -2
  35. data/app/lib/primer/tabbed_component_helper.rb +37 -0
  36. data/app/lib/primer/view_helper.rb +2 -2
  37. data/lib/primer/view_components/version.rb +1 -1
  38. data/static/statuses.json +1 -1
  39. metadata +5 -3
  40. data/app/components/primer/slot.rb +0 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0f3b2f2609173d59173576d7bd384ae8902540a1be4434930c9b982d3f86c50c
4
- data.tar.gz: 4d0d573d72270fcb808857fa502a9cda31279755dc7859121301e97ea6a1b305
3
+ metadata.gz: b994be67e7454dab595ebdf8745db530f855ef34a9ce292e6b8110ae4f2cf060
4
+ data.tar.gz: 33c5ee3a0e757c39434451c2c86ff32586add5f06636e4dfb6f89a52ac89cd59
5
5
  SHA512:
6
- metadata.gz: f14ba8ad8f0698e04791c839ac68f1f355c15d37436306c510589c3a67f1197cdc7449ee4301f87b5cecf6f0234c5d704c074ecdc52fd3d5dbad735d9b7bd6c9
7
- data.tar.gz: a6b4b86bd72500b3d853a5ca2f68a14b76188a6e219b33f091d992f509772dd7f0e707d1a609b2a8ff4e382f6237104b4423c5ba9bec6ca8a0b0cf8c7822417a
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 in pre-release development and should not be considered stable._
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
@@ -3,8 +3,6 @@
3
3
  module Primer
4
4
  # Use AvatarStack to stack multiple avatars together.
5
5
  class AvatarStackComponent < Primer::Component
6
- include ViewComponent::SlotableV2
7
-
8
6
  ALIGN_DEFAULT = :left
9
7
  ALIGN_OPTIONS = [ALIGN_DEFAULT, :right].freeze
10
8
 
@@ -2,7 +2,7 @@
2
2
  <% if spinner.present? %>
3
3
  <%= spinner %>
4
4
  <% elsif @icon.present? %>
5
- <%= primer_octicon icon: @icon, size: @icon_size, classes: "blankslate-icon" %>
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 %>
@@ -5,8 +5,6 @@ module Primer
5
5
  class BlankslateComponent < Primer::Component
6
6
  status :beta
7
7
 
8
- include ViewComponent::SlotableV2
9
-
10
8
  # Optional Spinner.
11
9
  #
12
10
  # @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::SpinnerComponent) %>.
@@ -5,8 +5,6 @@ module Primer
5
5
  class BorderBoxComponent < Primer::Component
6
6
  status :beta
7
7
 
8
- include ViewComponent::SlotableV2
9
-
10
8
  DEFAULT_PADDING = :default
11
9
  PADDING_MAPPINGS = {
12
10
  DEFAULT_PADDING => "",
@@ -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
@@ -3,7 +3,6 @@
3
3
  module Primer
4
4
  # Use DetailsComponent to reveal content after clicking a button.
5
5
  class DetailsComponent < Primer::Component
6
- include ViewComponent::SlotableV2
7
6
  status :beta
8
7
 
9
8
  NO_OVERLAY = :none
@@ -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 icon: @icon if @icon %>
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 icon: "x" %>
6
+ <%= primer_octicon "x" %>
7
7
  </button>
8
8
  <% end %>
9
9
 
@@ -5,8 +5,6 @@ module Primer
5
5
  class FlashComponent < Primer::Component
6
6
  status :beta
7
7
 
8
- include ViewComponent::SlotableV2
9
-
10
8
  # Optional action content showed on the right side of the component.
11
9
  #
12
10
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
@@ -3,8 +3,6 @@
3
3
  module Primer
4
4
  # Use Layout to build a main/sidebar layout.
5
5
  class LayoutComponent < Primer::Component
6
- include ViewComponent::SlotableV2
7
-
8
6
  # The main content
9
7
  #
10
8
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
@@ -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(icon: "check")) %>
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(icon: "check")) %>
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,9 @@
1
+ <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
+ <%= icon %>
3
+ <% if text.present? %>
4
+ <%= text %>
5
+ <% else %>
6
+ <%= content %>
7
+ <% end %>
8
+ <%= counter %>
9
+ <% 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(icon: "people", size: :medium)) %>
25
+ # <%= render(Primer::OcticonComponent.new("people", size: :medium)) %>
25
26
  #
26
27
  # @example Large
27
- # <%= render(Primer::OcticonComponent.new(icon: "x", size: :large)) %>
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:, size: SIZE_DEFAULT, **system_arguments)
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
@@ -3,7 +3,6 @@
3
3
  module Primer
4
4
  # Use ProgressBar to visualize task completion.
5
5
  class ProgressBarComponent < Primer::Component
6
- include ViewComponent::SlotableV2
7
6
  status :beta
8
7
 
9
8
  # Use the Item slot to add an item to the progress bas
@@ -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,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.
@@ -1,17 +1,15 @@
1
- <%= render wrapper.new(**@system_arguments) do %>
2
- <nav role="tablist" aria-label="<%= @aria_label %>" class="tabnav-tabs">
3
- <% tabs.each do |tab| %>
4
- <%= tab %>
5
- <% end %>
6
- </nav >
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
- <% if tab.panel.present? %>
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 ViewComponent::SlotableV2
6
+ include Primer::TabbedComponentHelper
7
7
 
8
- class MultipleSelectedTabsError < StandardError; end
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 { |**system_arguments|
17
- return TabComponent.new(**system_arguments) unless @with_panel
18
-
19
- TabComponent.new(tag: :button, type: :button, **system_arguments)
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, title: "Tab 1", href: "#") %>
25
- # <% c.tab(title: "Tab 2", href: "#") %>
26
- # <% c.tab(title: "Tab 3", href: "#") %>
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, title: "Tab 1") { "Panel 1" } %>
32
- # <% c.tab(title: "Tab 2") { "Panel 1" } %>
33
- # <% c.tab(title: "Tab 3") { "Panel 1" } %>
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(icon: @icon))
80
+ render(Primer::OcticonComponent.new(@icon))
82
81
  end
83
82
  end
84
83
  end
@@ -1,11 +1,23 @@
1
- <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
- <% if @align == :right %>
3
- <%= actions %>
4
- <% end %>
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
- <%= body %>
13
+ <% if @align == :left %>
14
+ <%= actions %>
15
+ <% end %>
16
+ <% end %>
7
17
 
8
- <% if @align == :left %>
9
- <%= actions %>
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 ViewComponent::SlotableV2
8
+ include Primer::TabbedComponentHelper
9
9
 
10
10
  ALIGN_DEFAULT = :left
11
11
  ALIGN_OPTIONS = [ALIGN_DEFAULT, :right].freeze
12
12
 
13
- # Use the body for the navigation items
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
- renders_one :body, lambda { |**system_arguments|
17
- system_arguments[:classes] = class_names("UnderlineNav-body", "list-style-none", system_arguments[:classes])
18
- system_arguments[:tag] ||= :ul
19
-
20
- Primer::BaseComponent.new(**system_arguments) { content }
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
- # Use actions for a call to action
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
- Primer::BaseComponent.new(**system_arguments) { content }
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.body do %>
35
- # <%= render(Primer::LinkComponent.new(href: "#url")) { "Item 1" } %>
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.body do %>
45
- # <%= render(Primer::LinkComponent.new(href: "#url")) { "Item 1" } %>
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
@@ -192,8 +192,8 @@ module Primer
192
192
  end
193
193
 
194
194
  if BOOLEAN_MAPPINGS.key?(key)
195
- BOOLEAN_MAPPINGS[key][:mappings].map { |m| m[:css_class] if m[:value] == val }.compact.each do |css_class|
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 |**component_args, &block|
16
- render component.constantize.new(**component_args), &block
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
@@ -5,7 +5,7 @@ module Primer
5
5
  module VERSION
6
6
  MAJOR = 0
7
7
  MINOR = 0
8
- PATCH = 31
8
+ PATCH = 32
9
9
 
10
10
  STRING = [MAJOR, MINOR, PATCH].join(".")
11
11
  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::TabNavComponent::TabComponent":"alpha","Primer::TextComponent":"beta","Primer::TimeAgoComponent":"alpha","Primer::TimelineItemComponent":"beta","Primer::TimelineItemComponent::BadgeComponent":"alpha","Primer::TooltipComponent":"alpha","Primer::TruncateComponent":"alpha","Primer::UnderlineNavComponent":"alpha"}
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.31
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-15 00:00:00.000000000 Z
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
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Primer
4
- # @private
5
- class Slot < ViewComponent::Slot
6
- include ClassNameHelper
7
- include FetchOrFallbackHelper
8
- include JoinStyleArgumentsHelper
9
- end
10
- end