primer_view_components 0.0.53 → 0.0.57

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +87 -0
  3. data/app/components/primer/alpha/tab_nav.html.erb +11 -0
  4. data/app/components/primer/alpha/tab_nav.rb +130 -0
  5. data/app/components/primer/{tab_nav_component.html.erb → alpha/tab_panels.html.erb} +3 -8
  6. data/app/components/primer/alpha/tab_panels.rb +82 -0
  7. data/app/components/primer/alpha/underline_nav.html.erb +15 -0
  8. data/app/components/primer/alpha/underline_nav.rb +137 -0
  9. data/app/components/primer/{underline_nav_component.html.erb → alpha/underline_panels.html.erb} +3 -8
  10. data/app/components/primer/alpha/underline_panels.rb +86 -0
  11. data/app/components/primer/base_component.rb +1 -1
  12. data/app/components/primer/{breadcrumb_component.html.erb → beta/breadcrumbs.html.erb} +2 -1
  13. data/app/components/primer/beta/breadcrumbs.rb +61 -0
  14. data/app/components/primer/navigation/tab_component.rb +7 -5
  15. data/app/components/primer/octicon_component.rb +6 -1
  16. data/app/components/primer/tab_container_component.rb +1 -1
  17. data/app/lib/primer/class_name_helper.rb +14 -13
  18. data/app/lib/primer/octicon/cache.rb +10 -2
  19. data/app/lib/primer/tab_nav_helper.rb +35 -0
  20. data/app/lib/primer/tabbed_component_helper.rb +4 -4
  21. data/app/lib/primer/underline_nav_helper.rb +44 -0
  22. data/lib/primer/classify/cache.rb +0 -6
  23. data/lib/primer/classify/utilities.rb +6 -2
  24. data/lib/primer/classify/utilities.yml +35 -0
  25. data/lib/primer/classify/validation.rb +1 -1
  26. data/lib/primer/classify.rb +0 -5
  27. data/lib/primer/view_components/engine.rb +1 -1
  28. data/lib/primer/view_components/linters/argument_mappers/button.rb +4 -1
  29. data/lib/primer/view_components/linters/flash_component_migration_counter.rb +5 -0
  30. data/lib/primer/view_components/version.rb +1 -1
  31. data/lib/rubocop/cop/primer/base_cop.rb +28 -0
  32. data/lib/rubocop/cop/primer/deprecated_arguments.rb +105 -15
  33. data/lib/rubocop/cop/primer/primer_octicon.rb +18 -1
  34. data/lib/rubocop/cop/primer/system_argument_instead_of_class.rb +1 -15
  35. data/lib/tasks/docs.rake +7 -6
  36. data/lib/tasks/utilities.rake +2 -0
  37. data/static/arguments.yml +75 -64
  38. data/static/classes.yml +2 -0
  39. data/static/constants.json +31 -29
  40. data/static/statuses.json +7 -5
  41. metadata +29 -9
  42. data/app/components/primer/breadcrumb_component.rb +0 -57
  43. data/app/components/primer/tab_nav_component.rb +0 -151
  44. data/app/components/primer/underline_nav_component.rb +0 -187
  45. data/lib/primer/classify/functional_text_colors.rb +0 -64
@@ -1,23 +1,18 @@
1
- <%= wrapper(**@wrapper_arguments) do %>
1
+ <%= tab_container_wrapper(with_panel: true, **@wrapper_arguments) do %>
2
2
  <%= render Primer::BaseComponent.new(**@system_arguments) do %>
3
3
  <% if @align == :right %>
4
4
  <%= actions %>
5
5
  <% end %>
6
-
7
6
  <%= render body do %>
8
7
  <% tabs.each do |tab| %>
9
8
  <%= tab %>
10
9
  <% end %>
11
10
  <% end %>
12
-
13
11
  <% if @align == :left %>
14
12
  <%= actions %>
15
13
  <% end %>
16
14
  <% end %>
17
-
18
- <% if @with_panel %>
19
- <% tabs.each do |tab| %>
20
- <%= tab.panel %>
21
- <% end %>
15
+ <% tabs.each do |tab| %>
16
+ <%= tab.panel %>
22
17
  <% end %>
23
18
  <% end %>
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Alpha
5
+ # Use `UnderlinePanels` to style tabs with an associated panel and an underlined selected state.
6
+ class UnderlinePanels < Primer::Component
7
+ include Primer::TabbedComponentHelper
8
+ include Primer::UnderlineNavHelper
9
+ # Use to render a button and an associated panel slot. See the example below or refer to <%= link_to_component(Primer::Navigation::TabComponent) %>.
10
+ #
11
+ # @param id [String] Unique ID of tab.
12
+ # @param selected [Boolean] Whether the tab is selected.
13
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
14
+ renders_many :tabs, lambda { |id:, selected: false, **system_arguments|
15
+ system_arguments[:id] = id
16
+ system_arguments[:classes] = underline_nav_tab_classes(system_arguments[:classes])
17
+
18
+ Primer::Navigation::TabComponent.new(
19
+ selected: selected,
20
+ with_panel: true,
21
+ list: true,
22
+ icon_classes: "UnderlineNav-octicon",
23
+ panel_id: "panel-#{id}",
24
+ **system_arguments
25
+ )
26
+ }
27
+
28
+ # Use actions for a call to action.
29
+ #
30
+ # @param tag [Symbol] (Primer::UnderlineNavHelper::ACTIONS_TAG_DEFAULT) <%= one_of(Primer::UnderlineNavHelper::ACTIONS_TAG_OPTIONS) %>
31
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
32
+ renders_one :actions, lambda { |tag: ACTIONS_TAG_DEFAULT, **system_arguments|
33
+ system_arguments[:tag] = fetch_or_fallback(ACTIONS_TAG_OPTIONS, tag, ACTIONS_TAG_DEFAULT)
34
+ system_arguments[:classes] = underline_nav_action_classes(system_arguments[:classes])
35
+
36
+ Primer::BaseComponent.new(**system_arguments)
37
+ }
38
+
39
+ # @example Default
40
+ # <%= render(Primer::Alpha::UnderlinePanels.new(label: "With panels")) do |component| %>
41
+ # <% component.tab(id: "tab-1", selected: true) do |t| %>
42
+ # <% t.text { "Tab 1" } %>
43
+ # <% t.panel do %>
44
+ # Panel 1
45
+ # <% end %>
46
+ # <% end %>
47
+ # <% component.tab(id: "tab-2") do |t| %>
48
+ # <% t.text { "Tab 2" } %>
49
+ # <% t.panel do %>
50
+ # Panel 2
51
+ # <% end %>
52
+ # <% end %>
53
+ # <% component.actions do %>
54
+ # <%= render(Primer::ButtonComponent.new) { "Button!" } %>
55
+ # <% end %>
56
+ # <% end %>
57
+ #
58
+ # @param label [String] Sets an `aria-label` that helps assistive technology users understand the purpose of the tabs.
59
+ # @param align [Symbol] <%= one_of(Primer::UnderlineNavHelper::ALIGN_OPTIONS) %> - Defaults to <%= Primer::UnderlineNavHelper::ALIGN_DEFAULT %>
60
+ # @param body_arguments [Hash] <%= link_to_system_arguments_docs %> for the body wrapper.
61
+ # @param wrapper_arguments [Hash] <%= link_to_system_arguments_docs %> for the `TabContainer` wrapper.
62
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
63
+ def initialize(label:, align: ALIGN_DEFAULT, body_arguments: {}, wrapper_arguments: {}, **system_arguments)
64
+ @align = fetch_or_fallback(ALIGN_OPTIONS, align, ALIGN_DEFAULT)
65
+ @wrapper_arguments = wrapper_arguments
66
+
67
+ @system_arguments = system_arguments
68
+ @system_arguments[:tag] = :div
69
+ @system_arguments[:classes] = underline_nav_classes(@system_arguments[:classes], @align)
70
+
71
+ @body_arguments = body_arguments
72
+ @body_arguments[:tag] = :ul
73
+ @body_arguments[:classes] = underline_nav_body_classes(@body_arguments[:classes])
74
+
75
+ @body_arguments[:role] = :tablist
76
+ @body_arguments[:"aria-label"] = label
77
+ end
78
+
79
+ private
80
+
81
+ def body
82
+ Primer::BaseComponent.new(**@body_arguments)
83
+ end
84
+ end
85
+ end
86
+ end
@@ -65,7 +65,7 @@ module Primer
65
65
  # | :- | :- | :- |
66
66
  # | `bg` | String, Symbol | Background color. Accepts either a hex value as a String or <%= one_of(Primer::Classify::FunctionalBackgroundColors::OPTIONS, lower: true) %> |
67
67
  # | `border_color` | Symbol | Border color. <%= one_of(Primer::Classify::FunctionalBorderColors::OPTIONS) %> |
68
- # | `color` | Symbol | Text color. <%= one_of(Primer::Classify::FunctionalTextColors::OPTIONS) %> |
68
+ # | `color` | Symbol | Text color. <%= one_of(Primer::Classify::Utilities.mappings(:color)) %> |
69
69
  #
70
70
  # ## Flex
71
71
  #
@@ -1,6 +1,7 @@
1
1
  <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
2
  <ol>
3
- <% items.each do |item| %>
3
+ <% items.each_with_index do |item, index| %>
4
+ <% item.selected = index == items.length - 1 %>
4
5
  <%= item %>
5
6
  <% end %>
6
7
  </ol>
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Beta
5
+ # Use `Breadcrumbs` to display page hierarchy.
6
+ class Breadcrumbs < Primer::Component
7
+ status :beta
8
+
9
+ # @param href [String] The URL to link to.
10
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
11
+ renders_many :items, "Item"
12
+
13
+ # @example Basic
14
+ # <%= render(Primer::Beta::Breadcrumbs.new) do |component| %>
15
+ # <% component.item(href: "/") do %>Home<% end %>
16
+ # <% component.item(href: "/about") do %>About<% end %>
17
+ # <% component.item(href: "/about/team") do %>Team<% end %>
18
+ # <% end %>
19
+ #
20
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
21
+ def initialize(**system_arguments)
22
+ @system_arguments = system_arguments
23
+ @system_arguments[:tag] = :nav
24
+ @system_arguments[:aria] = { label: "Breadcrumb" }
25
+ end
26
+
27
+ def render?
28
+ items.any?
29
+ end
30
+
31
+ # This component is part of `Primer::Beta::Breadcrumbs` and should not be
32
+ # used as a standalone component.
33
+ class Item < Primer::Component
34
+ attr_accessor :selected, :href
35
+
36
+ def initialize(href:, **system_arguments)
37
+ @href = href
38
+ @system_arguments = system_arguments
39
+ @selected = false
40
+
41
+ @system_arguments[:tag] = :li
42
+ @system_arguments[:classes] = "breadcrumb-item #{@system_arguments[:classes]}"
43
+ end
44
+
45
+ def call
46
+ link_arguments = { href: @href }
47
+
48
+ if selected
49
+ link_arguments[:"aria-current"] = "page"
50
+ link_arguments[:classes] = "breadcrumb-item-selected"
51
+ @system_arguments[:classes] = "#{@system_arguments[:classes]} breadcrumb-item-selected"
52
+ end
53
+
54
+ render(Primer::BaseComponent.new(**@system_arguments)) do
55
+ render(Primer::LinkComponent.new(**link_arguments)) { content }
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -2,8 +2,8 @@
2
2
 
3
3
  module Primer
4
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.
5
+ # This component is part of navigation components such as `Primer::Alpha::TabNav`
6
+ # and `Primer::Alpha::UnderlineNav` and should not be used by itself.
7
7
  #
8
8
  # @accessibility
9
9
  # `TabComponent` renders the selected anchor tab with `aria-current="page"` by default.
@@ -14,7 +14,7 @@ module Primer
14
14
  # Panel controlled by the Tab. This will not render anything in the tab itself.
15
15
  # It will provide a accessor for the Tab's parent to call and render the panel
16
16
  # content in the appropriate place.
17
- # Refer to `UnderlineNavComponent` and `TabNavComponent` implementations for examples.
17
+ # Refer to `UnderlineNav` and `TabNav` implementations for examples.
18
18
  #
19
19
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
20
20
  renders_one :panel, lambda { |**system_arguments|
@@ -111,19 +111,21 @@ module Primer
111
111
 
112
112
  @system_arguments = system_arguments
113
113
  @id = @system_arguments[:id]
114
+ @wrapper_arguments = wrapper_arguments
114
115
 
115
116
  if with_panel || @system_arguments[:tag] == :button
116
117
  @system_arguments[:tag] = :button
117
118
  @system_arguments[:type] = :button
118
119
  @system_arguments[:role] = :tab
119
120
  panel_id(panel_id)
121
+ # https://www.w3.org/TR/wai-aria-practices/#presentation_role
122
+ @wrapper_arguments[:role] = :presentation
120
123
  else
121
124
  @system_arguments[:tag] = :a
122
125
  end
123
126
 
124
- @wrapper_arguments = wrapper_arguments
125
127
  @wrapper_arguments[:tag] = :li
126
- @wrapper_arguments[:display] ||= :flex
128
+ @wrapper_arguments[:display] ||= :inline_flex
127
129
 
128
130
  return unless @selected
129
131
 
@@ -41,7 +41,12 @@ module Primer
41
41
  system_arguments.delete(:width)
42
42
  end
43
43
 
44
- cache_key = Primer::Octicon::Cache.get_key(symbol: icon_key, size: size, **system_arguments.slice(:height, :width))
44
+ cache_key = Primer::Octicon::Cache.get_key(
45
+ symbol: icon_key,
46
+ size: size,
47
+ height: system_arguments[:height],
48
+ width: system_arguments[:width]
49
+ )
45
50
 
46
51
  @system_arguments = system_arguments
47
52
  @system_arguments[:tag] = :svg
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Primer
4
4
  # Use `TabContainer` to create tabbed content with keyboard support. This component does not add any styles.
5
- # It only provides the tab functionality. If you want styled Tabs you can look at <%= link_to_component(Primer::TabNavComponent) %>.
5
+ # It only provides the tab functionality. If you want styled Tabs you can look at <%= link_to_component(Primer::Alpha::TabNav) %>.
6
6
  #
7
7
  # This component requires javascript.
8
8
  class TabContainerComponent < Primer::Component
@@ -7,22 +7,23 @@ module Primer
7
7
  # :nodoc:
8
8
  module ClassNameHelper
9
9
  def class_names(*args)
10
- classes = []
11
-
12
- args.each do |class_name|
13
- case class_name
14
- when String
15
- classes << class_name if class_name.present?
16
- when Hash
17
- class_name.each do |key, val|
18
- classes << key if val
10
+ [].tap do |classes|
11
+ args.each do |class_name|
12
+ case class_name
13
+ when String
14
+ classes << class_name if class_name.present?
15
+ when Hash
16
+ class_name.each do |key, val|
17
+ classes << key if val
18
+ end
19
+ when Array
20
+ classes << class_names(*class_name).presence
19
21
  end
20
- when Array
21
- classes << class_names(*class_name).presence
22
22
  end
23
- end
24
23
 
25
- classes.compact.uniq.join(" ")
24
+ classes.compact!
25
+ classes.uniq!
26
+ end.join(" ")
26
27
  end
27
28
  end
28
29
  end
@@ -9,8 +9,9 @@ module Primer
9
9
  PRELOADED_ICONS = [:alert, :check, :"chevron-down", :paste, :clock, :"dot-fill", :info, :"kebab-horizontal", :link, :lock, :mail, :pencil, :plus, :question, :repo, :search, :"shield-lock", :star, :trash, :x].freeze
10
10
 
11
11
  class << self
12
- def get_key(symbol:, size:, width: nil, height: nil)
13
- [symbol, size, width, height].join("_")
12
+ def get_key(**kwargs)
13
+ correct_key_args?(**kwargs)
14
+ kwargs.hash
14
15
  end
15
16
 
16
17
  def read(key)
@@ -36,6 +37,13 @@ module Primer
36
37
  def preload!
37
38
  PRELOADED_ICONS.each { |icon| Primer::OcticonComponent.new(icon: icon) }
38
39
  end
40
+
41
+ private
42
+
43
+ def correct_key_args?(symbol:, size:, width: nil, height: nil)
44
+ # This method does nothing but will raise an ArgumentError if the
45
+ # wrong args are passed.
46
+ end
39
47
  end
40
48
  end
41
49
  end
@@ -0,0 +1,35 @@
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 TabNavHelper
9
+ extend ActiveSupport::Concern
10
+
11
+ EXTRA_ALIGN_DEFAULT = :left
12
+ EXTRA_ALIGN_OPTIONS = [EXTRA_ALIGN_DEFAULT, :right].freeze
13
+
14
+ def tab_nav_tab_classes(classes)
15
+ class_names(
16
+ "tabnav-tab",
17
+ classes
18
+ )
19
+ end
20
+
21
+ def tab_nav_classes(classes)
22
+ class_names(
23
+ "tabnav",
24
+ classes
25
+ )
26
+ end
27
+
28
+ def tab_nav_body_classes(classes)
29
+ class_names(
30
+ "tabnav-tabs",
31
+ classes
32
+ )
33
+ end
34
+ end
35
+ end
@@ -16,12 +16,12 @@ module Primer
16
16
 
17
17
  private
18
18
 
19
- def navigation_tag(with_panel)
20
- with_panel ? :div : :nav
19
+ def aria_label_for_page_nav(label)
20
+ @system_arguments[:tag] == :nav ? @system_arguments[:"aria-label"] = label : @body_arguments[:"aria-label"] = label
21
21
  end
22
22
 
23
- def wrapper(**system_arguments)
24
- return yield unless @with_panel
23
+ def tab_container_wrapper(with_panel:, **system_arguments)
24
+ return yield unless with_panel
25
25
 
26
26
  render Primer::TabContainerComponent.new(**system_arguments) do
27
27
  yield if block_given?
@@ -0,0 +1,44 @@
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 UnderlineNavHelper
9
+ extend ActiveSupport::Concern
10
+
11
+ ALIGN_DEFAULT = :left
12
+ ALIGN_OPTIONS = [ALIGN_DEFAULT, :right].freeze
13
+
14
+ ACTIONS_TAG_DEFAULT = :div
15
+ ACTIONS_TAG_OPTIONS = [ACTIONS_TAG_DEFAULT, :span].freeze
16
+
17
+ def underline_nav_classes(classes, align)
18
+ class_names(
19
+ classes,
20
+ "UnderlineNav",
21
+ "UnderlineNav--right" => align == :right
22
+ )
23
+ end
24
+
25
+ def underline_nav_body_classes(classes)
26
+ class_names(
27
+ "UnderlineNav-body",
28
+ classes,
29
+ "list-style-none"
30
+ )
31
+ end
32
+
33
+ def underline_nav_action_classes(classes)
34
+ class_names("UnderlineNav-actions", classes)
35
+ end
36
+
37
+ def underline_nav_tab_classes(classes)
38
+ class_names(
39
+ "UnderlineNav-item",
40
+ classes
41
+ )
42
+ end
43
+ end
44
+ end
@@ -3,7 +3,6 @@
3
3
  require_relative "flex"
4
4
  require_relative "functional_background_colors"
5
5
  require_relative "functional_border_colors"
6
- require_relative "functional_text_colors"
7
6
  require_relative "grid"
8
7
 
9
8
  module Primer
@@ -55,11 +54,6 @@ module Primer
55
54
  values: Primer::Classify::Grid::COL_VALUES
56
55
  )
57
56
 
58
- preload(
59
- keys: [Primer::Classify::COLOR_KEY],
60
- values: Primer::Classify::FunctionalTextColors::OPTIONS
61
- )
62
-
63
57
  preload(
64
58
  keys: [Primer::Classify::BG_KEY],
65
59
  values: Primer::Classify::FunctionalBackgroundColors::OPTIONS