primer_view_components 0.1.0 → 0.1.2

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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -0
  3. data/app/assets/javascripts/primer_view_components.js +1 -1
  4. data/app/assets/javascripts/primer_view_components.js.map +1 -1
  5. data/app/assets/styles/primer_view_components.css +1 -1
  6. data/app/assets/styles/primer_view_components.css.map +1 -1
  7. data/app/components/primer/alpha/action_list/divider.rb +2 -2
  8. data/app/components/primer/alpha/action_list/heading.html.erb +1 -1
  9. data/app/components/primer/alpha/action_list/heading.rb +11 -5
  10. data/app/components/primer/alpha/action_list/item.rb +19 -15
  11. data/app/components/primer/alpha/action_list.html.erb +7 -8
  12. data/app/components/primer/alpha/action_list.rb +16 -11
  13. data/app/components/primer/alpha/nav_list/{section.rb → group.rb} +5 -5
  14. data/app/components/primer/alpha/nav_list/item.html.erb +1 -1
  15. data/app/components/primer/alpha/nav_list/item.rb +15 -1
  16. data/app/components/primer/alpha/nav_list.d.ts +1 -0
  17. data/app/components/primer/alpha/nav_list.html.erb +8 -8
  18. data/app/components/primer/alpha/nav_list.js +21 -0
  19. data/app/components/primer/alpha/nav_list.rb +30 -34
  20. data/app/components/primer/alpha/nav_list.ts +23 -0
  21. data/app/components/primer/alpha/navigation/tab.rb +168 -0
  22. data/app/components/primer/alpha/overlay/header.html.erb +2 -2
  23. data/app/components/primer/alpha/overlay.rb +29 -9
  24. data/app/components/primer/alpha/tab_nav.rb +10 -3
  25. data/app/components/primer/alpha/tab_panels.rb +2 -2
  26. data/app/components/primer/alpha/underline_nav.css +1 -1
  27. data/app/components/primer/alpha/underline_nav.css.map +1 -1
  28. data/app/components/primer/alpha/underline_nav.pcss +1 -0
  29. data/app/components/primer/alpha/underline_nav.rb +2 -2
  30. data/app/components/primer/alpha/underline_panels.rb +2 -2
  31. data/app/components/primer/beta/button.html.erb +1 -1
  32. data/app/components/primer/beta/button.rb +2 -1
  33. data/app/components/primer/component.rb +34 -0
  34. data/app/components/primer/navigation/tab_component.rb +3 -157
  35. data/app/components/primer/truncate.rb +1 -1
  36. data/lib/primer/deprecations.yml +9 -0
  37. data/lib/primer/forms/dsl/text_field_input.rb +1 -1
  38. data/lib/primer/forms/primer_text_field.js +17 -6
  39. data/lib/primer/forms/primer_text_field.ts +15 -7
  40. data/lib/primer/forms/text_field.html.erb +3 -3
  41. data/lib/primer/view_components/version.rb +1 -1
  42. data/lib/primer/yard/component_manifest.rb +2 -1
  43. data/lib/tasks/docs.rake +1 -1
  44. data/previews/primer/alpha/action_list_preview.rb +41 -29
  45. data/previews/primer/alpha/nav_list_preview/trailing_action.html.erb +19 -0
  46. data/previews/primer/alpha/nav_list_preview.rb +19 -30
  47. data/previews/primer/alpha/overlay_preview.rb +34 -4
  48. data/previews/primer/alpha/tab_nav_preview/with_extra.html.erb +8 -0
  49. data/previews/primer/alpha/tab_nav_preview.rb +5 -0
  50. data/previews/primer/alpha/tab_panels_preview/with_extra.html.erb +17 -0
  51. data/previews/primer/alpha/tab_panels_preview.rb +5 -0
  52. data/static/arguments.json +64 -8
  53. data/static/audited_at.json +2 -1
  54. data/static/constants.json +20 -8
  55. data/static/previews.json +20 -5
  56. data/static/statuses.json +4 -3
  57. metadata +10 -8
  58. data/app/components/primer/alpha/nav_list/section.html.erb +0 -3
  59. data/previews/primer/alpha/action_list_preview/heading.html.erb +0 -4
  60. /data/app/components/primer/{navigation/tab_component.html.erb → alpha/navigation/tab.html.erb} +0 -0
@@ -0,0 +1,168 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module Alpha
5
+ module Navigation
6
+ # This component is part of navigation components such as `Primer::Alpha::TabNav`
7
+ # and `Primer::Alpha::UnderlineNav` and should not be used by itself.
8
+ #
9
+ # @accessibility
10
+ # `Tab` renders the selected anchor tab with `aria-current="page"` by default.
11
+ # When the selected tab does not correspond to the current page, such as in a nested inner tab, make sure to use aria-current="true"
12
+ class Tab < Primer::Component
13
+ status :alpha
14
+
15
+ DEFAULT_ARIA_CURRENT_FOR_ANCHOR = :page
16
+ ARIA_CURRENT_OPTIONS_FOR_ANCHOR = [true, DEFAULT_ARIA_CURRENT_FOR_ANCHOR].freeze
17
+ # Panel controlled by the Tab. This will not render anything in the tab itself.
18
+ # It will provide a accessor for the Tab's parent to call and render the panel
19
+ # content in the appropriate place.
20
+ # Refer to `UnderlineNav` and `TabNav` implementations for examples.
21
+ #
22
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
23
+ renders_one :panel, lambda { |**system_arguments|
24
+ return unless @with_panel
25
+
26
+ deny_tag_argument(**system_arguments)
27
+ system_arguments[:id] = @panel_id
28
+ system_arguments[:tag] = :div
29
+ system_arguments[:role] ||= :tabpanel
30
+ system_arguments[:tabindex] = 0
31
+ system_arguments[:hidden] = true unless @selected
32
+
33
+ label_present = aria("label", system_arguments) || aria("labelledby", system_arguments)
34
+ unless label_present
35
+ if @id.present?
36
+ system_arguments[:"aria-labelledby"] = @id
37
+ elsif !Rails.env.production?
38
+ raise ArgumentError, "Panels must be labelled. Either set a unique `id` on the tab, or set an `aria-label` directly on the panel"
39
+ end
40
+ end
41
+
42
+ Primer::BaseComponent.new(**system_arguments)
43
+ }
44
+
45
+ # Icon to be rendered in the Tab left.
46
+ #
47
+ # @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::Beta::Octicon) %>.
48
+ renders_one :icon, lambda { |icon = nil, **system_arguments|
49
+ system_arguments[:classes] = class_names(
50
+ @icon_classes,
51
+ system_arguments[:classes]
52
+ )
53
+ Primer::Beta::Octicon.new(icon, **system_arguments)
54
+ }
55
+
56
+ # The Tab's text.
57
+ #
58
+ # @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::Beta::Text) %>.
59
+ renders_one :text, Primer::Beta::Text
60
+
61
+ # Counter to be rendered in the Tab right.
62
+ #
63
+ # @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::Beta::Counter) %>.
64
+ renders_one :counter, Primer::Beta::Counter
65
+
66
+ attr_reader :selected
67
+
68
+ # @example Default
69
+ # <%= render(Primer::Alpha::Navigation::Tab.new(selected: true)) do |component| %>
70
+ # <% component.with_text { "Selected" } %>
71
+ # <% end %>
72
+ # <%= render(Primer::Alpha::Navigation::Tab.new) do |component| %>
73
+ # <% component.with_text { "Not selected" } %>
74
+ # <% end %>
75
+ #
76
+ # @example With icons and counters
77
+ # <%= render(Primer::Alpha::Navigation::Tab.new) do |component| %>
78
+ # <% component.with_icon(:star) %>
79
+ # <% component.with_text { "Tab" } %>
80
+ # <% end %>
81
+ # <%= render(Primer::Alpha::Navigation::Tab.new) do |component| %>
82
+ # <% component.with_icon(:star) %>
83
+ # <% component.with_text { "Tab" } %>
84
+ # <% component.with_counter(count: 10) %>
85
+ # <% end %>
86
+ # <%= render(Primer::Alpha::Navigation::Tab.new) do |component| %>
87
+ # <% component.with_text { "Tab" } %>
88
+ # <% component.with_counter(count: 10) %>
89
+ # <% end %>
90
+ #
91
+ # @example Inside a list
92
+ # <%= render(Primer::Alpha::Navigation::Tab.new(list: true)) do |component| %>
93
+ # <% component.with_text { "Tab" } %>
94
+ # <% end %>
95
+ #
96
+ # @example With custom HTML
97
+ # <%= render(Primer::Alpha::Navigation::Tab.new) do %>
98
+ # <div>
99
+ # This is my <strong>custom HTML</strong>
100
+ # </div>
101
+ # <% end %>
102
+ #
103
+ # @param list [Boolean] Whether the Tab is an item in a `<ul>` list.
104
+ # @param selected [Boolean] Whether the Tab is selected or not.
105
+ # @param with_panel [Boolean] Whether the Tab has an associated panel.
106
+ # @param panel_id [String] Only applies if `with_panel` is `true`. Unique id of panel.
107
+ # @param icon_classes [Boolean] Classes that must always be applied to icons.
108
+ # @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.
109
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
110
+ def initialize(list: false, selected: false, with_panel: false, panel_id: "", icon_classes: "", wrapper_arguments: {}, **system_arguments)
111
+ @selected = selected
112
+ @icon_classes = icon_classes
113
+ @list = list
114
+ @with_panel = with_panel
115
+
116
+ @system_arguments = system_arguments
117
+ @id = @system_arguments[:id]
118
+ @wrapper_arguments = wrapper_arguments
119
+
120
+ if with_panel || @system_arguments[:tag] == :button
121
+ @system_arguments[:tag] = :button
122
+ @system_arguments[:type] = :button
123
+ @system_arguments[:role] = :tab
124
+ panel_id(panel_id)
125
+ # https://www.w3.org/TR/wai-aria-practices/#presentation_role
126
+ @wrapper_arguments[:role] = :presentation
127
+ else
128
+ @system_arguments[:tag] = :a
129
+ end
130
+
131
+ @wrapper_arguments[:tag] = :li
132
+ @wrapper_arguments[:display] ||= :inline_flex
133
+
134
+ return unless @selected
135
+
136
+ if @system_arguments[:tag] == :a
137
+ aria_current = aria("current", system_arguments) || DEFAULT_ARIA_CURRENT_FOR_ANCHOR
138
+ @system_arguments[:"aria-current"] = fetch_or_fallback(ARIA_CURRENT_OPTIONS_FOR_ANCHOR, aria_current, DEFAULT_ARIA_CURRENT_FOR_ANCHOR)
139
+ else
140
+ @system_arguments[:"aria-selected"] = true
141
+ end
142
+ end
143
+
144
+ def wrapper
145
+ unless @list
146
+ yield
147
+ return # returning `yield` caused a double render
148
+ end
149
+
150
+ render(Primer::BaseComponent.new(**@wrapper_arguments)) do
151
+ yield if block_given?
152
+ end
153
+ end
154
+
155
+ private
156
+
157
+ def panel_id(panel_id)
158
+ if panel_id.blank?
159
+ raise ArgumentError, "`panel_id` is required" unless Rails.env.production?
160
+ else
161
+ @panel_id = panel_id
162
+ @system_arguments[:"aria-controls"] = @panel_id
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
@@ -1,11 +1,11 @@
1
1
  <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
2
  <div class="Overlay-headerContentWrap">
3
3
  <div class="Overlay-titleWrap">
4
- <h1 class="Overlay-title <% if @visually_hide_title || content.present? %>sr-only<% end %>"><%= @title %></h1>
4
+ <h1 id="<%= @id %>" class="Overlay-title <% if @visually_hide_title || content.present? %>sr-only<% end %>"><%= @title %></h1>
5
5
  <% if content.present? %>
6
6
  <%= content %>
7
7
  <% elsif @subtitle.present? %>
8
- <h2 id="<%= @id %>-description" class="Overlay-description"><%= @subtitle %></h2>
8
+ <h2 class="Overlay-description"><%= @subtitle %></h2>
9
9
  <% end %>
10
10
  </div>
11
11
  <div class="Overlay-actionWrap">
@@ -68,14 +68,18 @@ module Primer
68
68
  # Optional button to open the Overlay.
69
69
  #
70
70
  # @param system_arguments [Hash] The same arguments as <%= link_to_component(Primer::ButtonComponent) %>.
71
- renders_one :show_button, lambda { |**system_arguments|
71
+ renders_one :show_button, lambda { |icon: nil, **system_arguments|
72
72
  system_arguments[:classes] = class_names(
73
73
  system_arguments[:classes]
74
74
  )
75
- system_arguments[:id] = "overlay-show-#{@system_arguments[:id]}"
76
- system_arguments["popovertoggletarget"] = @system_arguments[:id]
77
- system_arguments[:data] = (system_arguments[:data] || {}).merge({ "show-dialog-id": @system_arguments[:id] })
78
- Primer::Beta::Button.new(**system_arguments)
75
+ system_arguments[:id] = show_button_id
76
+ system_arguments["popovertoggletarget"] = overlay_id
77
+ system_arguments[:aria] = (system_arguments[:aria] || {}).merge({ controls: overlay_id, haspopup: "true" })
78
+ if icon.present?
79
+ Primer::Beta::IconButton.new(icon: icon, **system_arguments)
80
+ else
81
+ Primer::Beta::Button.new(**system_arguments)
82
+ end
79
83
  }
80
84
 
81
85
  # Header content.
@@ -85,7 +89,7 @@ module Primer
85
89
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
86
90
  renders_one :header, lambda { |divider: false, size: :medium, visually_hide_title: @visually_hide_title, **system_arguments|
87
91
  Primer::Alpha::Overlay::Header.new(
88
- id: @id,
92
+ id: title_id,
89
93
  title: @title,
90
94
  subtitle: @subtitle,
91
95
  size: size,
@@ -165,7 +169,6 @@ module Primer
165
169
  @system_arguments[:classes] = class_names(
166
170
  "Overlay",
167
171
  SIZE_MAPPINGS[fetch_or_fallback(SIZE_OPTIONS, size, DEFAULT_SIZE)],
168
- "Overlay--motion-scaleFade",
169
172
  system_arguments[:classes]
170
173
  )
171
174
  @system_arguments[:tag] = "anchored-position"
@@ -182,13 +185,30 @@ module Primer
182
185
 
183
186
  @system_arguments[:popover] = popover
184
187
  @system_arguments[:aria] ||= {}
185
- @system_arguments[:aria][:describedby] ||= "#{@id}-description"
186
188
  end
187
189
 
188
190
  def before_render
189
- with_header unless header?
191
+ if header?
192
+ @system_arguments[:aria][:labelledby] ||= title_id
193
+ else
194
+ @system_arguments[:aria][:label] = @title
195
+ end
190
196
  with_body unless body?
191
197
  end
198
+
199
+ private
200
+
201
+ def overlay_id
202
+ @system_arguments[:id]
203
+ end
204
+
205
+ def title_id
206
+ "overlay-title-#{overlay_id}"
207
+ end
208
+
209
+ def show_button_id
210
+ "overlay-show-#{overlay_id}"
211
+ end
192
212
  end
193
213
  end
194
214
  end
@@ -9,7 +9,7 @@ module Primer
9
9
  # - By default, `TabNav` renders links within a `<nav>` element. `<nav>` has an
10
10
  # implicit landmark role of `navigation` which should be reserved for main links.
11
11
  # For all other set of links, set tag to `:div`.
12
- # - See <%= link_to_component(Primer::Navigation::TabComponent) %> for additional
12
+ # - See <%= link_to_component(Primer::Alpha::Navigation::Tab) %> for additional
13
13
  # accessibility considerations.
14
14
  class TabNav < Primer::Component
15
15
  include Primer::TabbedComponentHelper
@@ -22,13 +22,13 @@ module Primer
22
22
  TAG_DEFAULT = :nav
23
23
  TAG_OPTIONS = [TAG_DEFAULT, :div].freeze
24
24
 
25
- # Tabs to be rendered. For more information, refer to <%= link_to_component(Primer::Navigation::TabComponent) %>.
25
+ # Tabs to be rendered. For more information, refer to <%= link_to_component(Primer::Alpha::Navigation::Tab) %>.
26
26
  #
27
27
  # @param selected [Boolean] Whether the tab is selected.
28
28
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
29
29
  renders_many :tabs, lambda { |selected: false, **system_arguments|
30
30
  system_arguments[:classes] = tab_nav_tab_classes(system_arguments[:classes])
31
- Primer::Navigation::TabComponent.new(
31
+ Primer::Alpha::Navigation::Tab.new(
32
32
  list: true,
33
33
  selected: selected,
34
34
  **system_arguments
@@ -124,6 +124,13 @@ module Primer
124
124
 
125
125
  aria_label_for_page_nav(label)
126
126
  end
127
+
128
+ def before_render
129
+ # Eagerly evaluate content to avoid https://github.com/primer/view_components/issues/1790
130
+ content
131
+
132
+ super
133
+ end
127
134
  end
128
135
  end
129
136
  end
@@ -14,7 +14,7 @@ module Primer
14
14
  TAG_DEFAULT = :nav
15
15
  TAG_OPTIONS = [TAG_DEFAULT, :div].freeze
16
16
 
17
- # Tabs to be rendered. For more information, refer to <%= link_to_component(Primer::Navigation::TabComponent) %>.
17
+ # Tabs to be rendered. For more information, refer to <%= link_to_component(Primer::Alpha::Navigation::Tab) %>.
18
18
  #
19
19
  # @param id [String] Unique ID of tab.
20
20
  # @param selected [Boolean] Whether the tab is selected.
@@ -23,7 +23,7 @@ module Primer
23
23
  system_arguments[:id] = id
24
24
  system_arguments[:classes] = tab_nav_tab_classes(system_arguments[:classes])
25
25
 
26
- Primer::Navigation::TabComponent.new(
26
+ Primer::Alpha::Navigation::Tab.new(
27
27
  selected: selected,
28
28
  with_panel: true,
29
29
  list: true,
@@ -1 +1 @@
1
- .UnderlineNav{-webkit-overflow-scrolling:auto;box-shadow:inset 0 -1px 0 var(--color-border-muted);display:flex;justify-content:space-between;min-height:var(--base-size-48,48px);overflow-x:auto;overflow-y:hidden}.UnderlineNav .Counter{background-color:var(--color-neutral-muted);color:var(--color-fg-default);margin-left:var(--primer-control-medium-gap,8px)}.UnderlineNav .Counter--primary{background-color:var(--color-neutral-emphasis);color:var(--color-fg-on-emphasis)}.UnderlineNav-body{align-items:center;display:flex;gap:var(--primer-control-medium-gap,8px);list-style:none}.UnderlineNav-item{align-items:center;background-color:initial;border:0;border-radius:var(--primer-borderRadius-medium,6px);color:var(--color-fg-default);cursor:pointer;display:flex;font-size:var(--primer-text-body-size-medium,14px);line-height:30px;padding:0 var(--primer-control-medium-paddingInline-condensed,8px);position:relative;text-align:center;white-space:nowrap}.UnderlineNav-item:focus,.UnderlineNav-item:focus-visible,.UnderlineNav-item:hover{border-bottom-color:var(--color-neutral-muted);color:var(--color-fg-default);outline-offset:-2px;text-decoration:none;transition:border-bottom-color .12s ease-out}.UnderlineNav-item [data-content]:before{content:attr(data-content);display:block;font-weight:var(--base-text-weight-semibold,600);height:0;visibility:hidden}.UnderlineNav-item:before{content:"";height:100%;left:50%;min-height:48px;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%);width:100%}@media (pointer:fine){.UnderlineNav-item:hover{background:var(--color-action-list-item-default-hover-bg);color:var(--color-fg-default);text-decoration:none;transition:background .12s ease-out}}.UnderlineNav-item.selected,.UnderlineNav-item[aria-current]:not([aria-current=false]),.UnderlineNav-item[role=tab][aria-selected=true]{border-bottom-color:var(--color-primer-border-active);color:var(--color-fg-default);font-weight:var(--base-text-weight-semibold,600)}.UnderlineNav-item.selected:after,.UnderlineNav-item[aria-current]:not([aria-current=false]):after,.UnderlineNav-item[role=tab][aria-selected=true]:after{background:var(--color-primer-border-active);border-radius:var(--primer-borderRadius-medium,6px);bottom:calc(50% - 25px);content:"";height:2px;position:absolute;right:50%;transform:translate(50%,-50%);width:100%}.UnderlineNav--right{justify-content:flex-end}.UnderlineNav--right .UnderlineNav-actions{flex:1 1 auto}.UnderlineNav-actions{align-self:center}.UnderlineNav--full{display:block}.UnderlineNav--full .UnderlineNav-body{min-height:var(--base-size-48,48px)}.UnderlineNav-octicon{fill:var(--color-fg-muted);color:var(--color-fg-muted);display:inline!important;margin-right:var(--primer-control-medium-gap,8px)}.UnderlineNav-container{display:flex;justify-content:space-between}
1
+ .UnderlineNav{-webkit-overflow-scrolling:auto;box-shadow:inset 0 -1px 0 var(--color-border-muted);display:flex;justify-content:space-between;min-height:var(--base-size-48,48px);overflow-x:auto;overflow-y:hidden}.UnderlineNav .Counter{background-color:var(--color-neutral-muted);color:var(--color-fg-default);margin-left:var(--primer-control-medium-gap,8px)}.UnderlineNav .Counter--primary{background-color:var(--color-neutral-emphasis);color:var(--color-fg-on-emphasis)}.UnderlineNav-body{align-items:center;display:flex;gap:var(--primer-control-medium-gap,8px);list-style:none}.UnderlineNav-item{align-items:center;background-color:initial;border:0;border-radius:var(--primer-borderRadius-medium,6px);color:var(--color-fg-default);cursor:pointer;display:flex;font-size:var(--primer-text-body-size-medium,14px);line-height:30px;padding:0 var(--primer-control-medium-paddingInline-condensed,8px);position:relative;text-align:center;white-space:nowrap}.UnderlineNav-item:focus,.UnderlineNav-item:focus-visible,.UnderlineNav-item:hover{border-bottom-color:var(--color-neutral-muted);color:var(--color-fg-default);outline-offset:-2px;text-decoration:none;transition:border-bottom-color .12s ease-out}.UnderlineNav-item [data-content]:before{content:attr(data-content);display:block;font-weight:var(--base-text-weight-semibold,600);height:0;visibility:hidden}.UnderlineNav-item:before{content:"";height:100%;left:50%;min-height:48px;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%);width:100%}@media (pointer:fine){.UnderlineNav-item:hover{background:var(--color-action-list-item-default-hover-bg);color:var(--color-fg-default);text-decoration:none;transition:background .12s ease-out}}.UnderlineNav-item.selected,.UnderlineNav-item[aria-current]:not([aria-current=false]),.UnderlineNav-item[role=tab][aria-selected=true]{border-bottom-color:var(--color-primer-border-active);color:var(--color-fg-default);font-weight:var(--base-text-weight-semibold,600)}.UnderlineNav-item.selected:after,.UnderlineNav-item[aria-current]:not([aria-current=false]):after,.UnderlineNav-item[role=tab][aria-selected=true]:after{background:var(--color-primer-border-active);border-radius:var(--primer-borderRadius-medium,6px);bottom:calc(50% - 25px);content:"";height:2px;position:absolute;right:50%;transform:translate(50%,-50%);width:100%;z-index:1}.UnderlineNav--right{justify-content:flex-end}.UnderlineNav--right .UnderlineNav-actions{flex:1 1 auto}.UnderlineNav-actions{align-self:center}.UnderlineNav--full{display:block}.UnderlineNav--full .UnderlineNav-body{min-height:var(--base-size-48,48px)}.UnderlineNav-octicon{fill:var(--color-fg-muted);color:var(--color-fg-muted);display:inline!important;margin-right:var(--primer-control-medium-gap,8px)}.UnderlineNav-container{display:flex;justify-content:space-between}
@@ -1 +1 @@
1
- {"version":3,"sources":["underline_nav.pcss","<no source>"],"names":[],"mappings":"AAEA,cAME,+BAAgC,CADhC,mDAAoD,CAJpD,YAAa,CAMb,6BAA8B,CAL9B,mCAAqC,CACrC,eAAgB,CAChB,iBAeF,CAVE,uBAGE,2CAA4C,CAD5C,6BAA8B,CAD9B,gDAGF,CAEA,gCAEE,8CAA+C,CAD/C,iCAEF,CAGF,mBAEE,kBAAmB,CADnB,YAAa,CAEb,wCAA0C,CAC1C,eACF,CAEA,mBAaE,kBAAmB,CAHnB,wBAA6B,CAC7B,QAAS,CACT,mDAAqD,CANrD,6BAA8B,CAG9B,cAAe,CAPf,YAAa,CAEb,kDAAoD,CACpD,gBAAiB,CAFjB,kEAAoE,CAFpE,iBAAkB,CAMlB,iBAAkB,CAClB,kBA6DF,CAtDE,mFAKE,8CAA+C,CAF/C,6BAA8B,CAG9B,mBAAoB,CAFpB,oBAAqB,CAGrB,4CACF,CAGA,yCAKE,0BAA2B,CAJ3B,aAAc,CAEd,gDAAkD,CADlD,QAAS,CAET,iBAEF,CAIE,0BClEJ,WAAA,YAAA,SAAA,gBAAA,kBAAA,QAAA,4CAAA,UDkE8B,CAI5B,sBACE,yBAGE,yDAA0D,CAF1D,6BAA8B,CAC9B,oBAAqB,CAErB,mCACF,CACF,CAEA,wIAKE,qDAAsD,CADtD,6BAA8B,CAD9B,gDAgBF,CAXE,0JAOE,4CAA6C,CAC7C,mDAAqD,CALrD,uBAAwB,CAGxB,UAAW,CADX,UAAW,CAJX,iBAAkB,CAClB,SAAU,CAOV,6BAA+B,CAL/B,UAMF,CAIJ,qBACE,wBAKF,CAHE,2CACE,aACF,CAGF,sBACE,iBACF,CAEA,oBACE,aAMF,CAHE,uCACE,mCACF,CAGF,sBAIE,0BAA2B,CAD3B,2BAA4B,CAF5B,wBAA0B,CAC1B,iDAGF,CAEA,wBACE,YAAa,CACb,6BACF","file":"underline_nav.css","sourcesContent":["/* UnderlineNav */\n\n.UnderlineNav {\n display: flex;\n min-height: var(--base-size-48, 48px);\n overflow-x: auto;\n overflow-y: hidden;\n box-shadow: inset 0 -1px 0 var(--color-border-muted);\n -webkit-overflow-scrolling: auto;\n justify-content: space-between;\n\n & .Counter {\n margin-left: var(--primer-control-medium-gap, 8px);\n color: var(--color-fg-default);\n background-color: var(--color-neutral-muted);\n }\n\n & .Counter--primary {\n color: var(--color-fg-on-emphasis);\n background-color: var(--color-neutral-emphasis);\n }\n}\n\n.UnderlineNav-body {\n display: flex;\n align-items: center;\n gap: var(--primer-control-medium-gap, 8px);\n list-style: none;\n}\n\n.UnderlineNav-item {\n position: relative;\n display: flex;\n padding: 0 var(--primer-control-medium-paddingInline-condensed, 8px);\n font-size: var(--primer-text-body-size-medium, 14px);\n line-height: 30px;\n color: var(--color-fg-default);\n text-align: center;\n white-space: nowrap;\n cursor: pointer;\n background-color: transparent;\n border: 0;\n border-radius: var(--primer-borderRadius-medium, 6px);\n align-items: center;\n\n &:hover,\n &:focus,\n &:focus-visible {\n color: var(--color-fg-default);\n text-decoration: none;\n border-bottom-color: var(--color-neutral-muted);\n outline-offset: -2px;\n transition: border-bottom-color 0.12s ease-out;\n }\n\n /* renders a visibly hidden \"copy\" of the label in bold, reserving box space for when label becomes bold on selected */\n & [data-content]::before {\n display: block;\n height: 0;\n font-weight: var(--base-text-weight-semibold, 600);\n visibility: hidden;\n content: attr(data-content);\n }\n\n /* increase touch target area */\n &::before {\n @mixin minTouchTarget 48px;\n }\n\n /* hover state was \"sticking\" on mobile after click */\n @media (pointer: fine) {\n &:hover {\n color: var(--color-fg-default);\n text-decoration: none;\n background: var(--color-action-list-item-default-hover-bg);\n transition: background 0.12s ease-out;\n }\n }\n\n &.selected,\n &[role='tab'][aria-selected='true'],\n &[aria-current]:not([aria-current='false']) {\n font-weight: var(--base-text-weight-semibold, 600);\n color: var(--color-fg-default);\n border-bottom-color: var(--color-primer-border-active);\n\n /* current/selected underline */\n &::after {\n position: absolute;\n right: 50%;\n bottom: calc(50% - 25px); /* 48px total height / 2 (24px) + 1px */\n width: 100%;\n height: 2px;\n content: '';\n background: var(--color-primer-border-active);\n border-radius: var(--primer-borderRadius-medium, 6px);\n transform: translate(50%, -50%);\n }\n }\n}\n\n.UnderlineNav--right {\n justify-content: flex-end;\n\n & .UnderlineNav-actions {\n flex: 1 1 auto;\n }\n}\n\n.UnderlineNav-actions {\n align-self: center;\n}\n\n.UnderlineNav--full {\n display: block;\n\n /* required for underline to align with additional wrapper element */\n & .UnderlineNav-body {\n min-height: var(--base-size-48, 48px);\n }\n}\n\n.UnderlineNav-octicon {\n display: inline !important;\n margin-right: var(--primer-control-medium-gap, 8px);\n color: var(--color-fg-muted);\n fill: var(--color-fg-muted);\n}\n\n.UnderlineNav-container {\n display: flex;\n justify-content: space-between;\n}\n",null]}
1
+ {"version":3,"sources":["underline_nav.pcss","<no source>"],"names":[],"mappings":"AAEA,cAME,+BAAgC,CADhC,mDAAoD,CAJpD,YAAa,CAMb,6BAA8B,CAL9B,mCAAqC,CACrC,eAAgB,CAChB,iBAeF,CAVE,uBAGE,2CAA4C,CAD5C,6BAA8B,CAD9B,gDAGF,CAEA,gCAEE,8CAA+C,CAD/C,iCAEF,CAGF,mBAEE,kBAAmB,CADnB,YAAa,CAEb,wCAA0C,CAC1C,eACF,CAEA,mBAaE,kBAAmB,CAHnB,wBAA6B,CAC7B,QAAS,CACT,mDAAqD,CANrD,6BAA8B,CAG9B,cAAe,CAPf,YAAa,CAEb,kDAAoD,CACpD,gBAAiB,CAFjB,kEAAoE,CAFpE,iBAAkB,CAMlB,iBAAkB,CAClB,kBA8DF,CAvDE,mFAKE,8CAA+C,CAF/C,6BAA8B,CAG9B,mBAAoB,CAFpB,oBAAqB,CAGrB,4CACF,CAGA,yCAKE,0BAA2B,CAJ3B,aAAc,CAEd,gDAAkD,CADlD,QAAS,CAET,iBAEF,CAIE,0BClEJ,WAAA,YAAA,SAAA,gBAAA,kBAAA,QAAA,4CAAA,UDkE8B,CAI5B,sBACE,yBAGE,yDAA0D,CAF1D,6BAA8B,CAC9B,oBAAqB,CAErB,mCACF,CACF,CAEA,wIAKE,qDAAsD,CADtD,6BAA8B,CAD9B,gDAiBF,CAZE,0JAQE,4CAA6C,CAC7C,mDAAqD,CALrD,uBAAwB,CAGxB,UAAW,CADX,UAAW,CALX,iBAAkB,CAElB,SAAU,CAOV,6BAA+B,CAL/B,UAAW,CAHX,SASF,CAIJ,qBACE,wBAKF,CAHE,2CACE,aACF,CAGF,sBACE,iBACF,CAEA,oBACE,aAMF,CAHE,uCACE,mCACF,CAGF,sBAIE,0BAA2B,CAD3B,2BAA4B,CAF5B,wBAA0B,CAC1B,iDAGF,CAEA,wBACE,YAAa,CACb,6BACF","file":"underline_nav.css","sourcesContent":["/* UnderlineNav */\n\n.UnderlineNav {\n display: flex;\n min-height: var(--base-size-48, 48px);\n overflow-x: auto;\n overflow-y: hidden;\n box-shadow: inset 0 -1px 0 var(--color-border-muted);\n -webkit-overflow-scrolling: auto;\n justify-content: space-between;\n\n & .Counter {\n margin-left: var(--primer-control-medium-gap, 8px);\n color: var(--color-fg-default);\n background-color: var(--color-neutral-muted);\n }\n\n & .Counter--primary {\n color: var(--color-fg-on-emphasis);\n background-color: var(--color-neutral-emphasis);\n }\n}\n\n.UnderlineNav-body {\n display: flex;\n align-items: center;\n gap: var(--primer-control-medium-gap, 8px);\n list-style: none;\n}\n\n.UnderlineNav-item {\n position: relative;\n display: flex;\n padding: 0 var(--primer-control-medium-paddingInline-condensed, 8px);\n font-size: var(--primer-text-body-size-medium, 14px);\n line-height: 30px;\n color: var(--color-fg-default);\n text-align: center;\n white-space: nowrap;\n cursor: pointer;\n background-color: transparent;\n border: 0;\n border-radius: var(--primer-borderRadius-medium, 6px);\n align-items: center;\n\n &:hover,\n &:focus,\n &:focus-visible {\n color: var(--color-fg-default);\n text-decoration: none;\n border-bottom-color: var(--color-neutral-muted);\n outline-offset: -2px;\n transition: border-bottom-color 0.12s ease-out;\n }\n\n /* renders a visibly hidden \"copy\" of the label in bold, reserving box space for when label becomes bold on selected */\n & [data-content]::before {\n display: block;\n height: 0;\n font-weight: var(--base-text-weight-semibold, 600);\n visibility: hidden;\n content: attr(data-content);\n }\n\n /* increase touch target area */\n &::before {\n @mixin minTouchTarget 48px;\n }\n\n /* hover state was \"sticking\" on mobile after click */\n @media (pointer: fine) {\n &:hover {\n color: var(--color-fg-default);\n text-decoration: none;\n background: var(--color-action-list-item-default-hover-bg);\n transition: background 0.12s ease-out;\n }\n }\n\n &.selected,\n &[role='tab'][aria-selected='true'],\n &[aria-current]:not([aria-current='false']) {\n font-weight: var(--base-text-weight-semibold, 600);\n color: var(--color-fg-default);\n border-bottom-color: var(--color-primer-border-active);\n\n /* current/selected underline */\n &::after {\n position: absolute;\n z-index: 1; /* raise above full-width flash banner */\n right: 50%;\n bottom: calc(50% - 25px); /* 48px total height / 2 (24px) + 1px */\n width: 100%;\n height: 2px;\n content: '';\n background: var(--color-primer-border-active);\n border-radius: var(--primer-borderRadius-medium, 6px);\n transform: translate(50%, -50%);\n }\n }\n}\n\n.UnderlineNav--right {\n justify-content: flex-end;\n\n & .UnderlineNav-actions {\n flex: 1 1 auto;\n }\n}\n\n.UnderlineNav-actions {\n align-self: center;\n}\n\n.UnderlineNav--full {\n display: block;\n\n /* required for underline to align with additional wrapper element */\n & .UnderlineNav-body {\n min-height: var(--base-size-48, 48px);\n }\n}\n\n.UnderlineNav-octicon {\n display: inline !important;\n margin-right: var(--primer-control-medium-gap, 8px);\n color: var(--color-fg-muted);\n fill: var(--color-fg-muted);\n}\n\n.UnderlineNav-container {\n display: flex;\n justify-content: space-between;\n}\n",null]}
@@ -87,6 +87,7 @@
87
87
  /* current/selected underline */
88
88
  &::after {
89
89
  position: absolute;
90
+ z-index: 1; /* raise above full-width flash banner */
90
91
  right: 50%;
91
92
  bottom: calc(50% - 25px); /* 48px total height / 2 (24px) + 1px */
92
93
  width: 100%;
@@ -12,7 +12,7 @@ module Primer
12
12
  # - By default, `UnderlineNav` renders links within a `<nav>` element. `<nav>` has an
13
13
  # implicit landmark role of `navigation` which should be reserved for main links.
14
14
  # For all other set of links, set tag to `:div`.
15
- # - See <%= link_to_component(Primer::Navigation::TabComponent) %> for additional
15
+ # - See <%= link_to_component(Primer::Alpha::Navigation::Tab) %> for additional
16
16
  # accessibility considerations.
17
17
  class UnderlineNav < Primer::Component
18
18
  include Primer::TabbedComponentHelper
@@ -29,7 +29,7 @@ module Primer
29
29
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
30
30
  renders_many :tabs, lambda { |selected: false, **system_arguments|
31
31
  system_arguments[:classes] = underline_nav_tab_classes(system_arguments[:classes])
32
- Primer::Navigation::TabComponent.new(
32
+ Primer::Alpha::Navigation::Tab.new(
33
33
  list: true,
34
34
  selected: selected,
35
35
  icon_classes: "UnderlineNav-octicon",
@@ -6,7 +6,7 @@ module Primer
6
6
  class UnderlinePanels < Primer::Component
7
7
  include Primer::TabbedComponentHelper
8
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) %>.
9
+ # Use to render a button and an associated panel slot. See the example below or refer to <%= link_to_component(Primer::Alpha::Navigation::Tab) %>.
10
10
  #
11
11
  # @param id [String] Unique ID of tab.
12
12
  # @param selected [Boolean] Whether the tab is selected.
@@ -15,7 +15,7 @@ module Primer
15
15
  system_arguments[:id] = id
16
16
  system_arguments[:classes] = underline_nav_tab_classes(system_arguments[:classes])
17
17
 
18
- Primer::Navigation::TabComponent.new(
18
+ Primer::Alpha::Navigation::Tab.new(
19
19
  selected: selected,
20
20
  with_panel: true,
21
21
  list: true,
@@ -1,4 +1,4 @@
1
- <%= render Primer::ConditionalWrapper.new(condition: tooltip.present?, tag: :div, classes: "Button-withTooltip") do -%>
1
+ <%= render Primer::ConditionalWrapper.new(condition: tooltip.present?, tag: :div, display: (:block if @block), classes: "Button-withTooltip") do -%>
2
2
  <%= render Primer::Beta::BaseButton.new(**@system_arguments) do -%>
3
3
  <span class="<%= @align_content_classes %>">
4
4
  <% if leading_visual %>
@@ -144,6 +144,7 @@ module Primer
144
144
  **system_arguments
145
145
  )
146
146
  @scheme = scheme
147
+ @block = block
147
148
 
148
149
  @system_arguments = system_arguments
149
150
 
@@ -162,7 +163,7 @@ module Primer
162
163
  SCHEME_MAPPINGS[fetch_or_fallback(SCHEME_OPTIONS, scheme, DEFAULT_SCHEME)],
163
164
  SIZE_MAPPINGS[fetch_or_fallback(SIZE_OPTIONS, size, DEFAULT_SIZE)],
164
165
  "Button",
165
- "Button--fullWidth" => block
166
+ "Button--fullWidth" => @block
166
167
  )
167
168
  end
168
169
 
@@ -58,6 +58,40 @@ module Primer
58
58
  system_arguments[:"aria-#{val}"] || system_arguments.dig(:aria, val.to_sym)
59
59
  end
60
60
 
61
+ # Merges hashes that contain "aria-*" keys and nested aria: hashes. Removes keys from
62
+ # each hash and returns them in the new hash.
63
+ #
64
+ # Eg. merge_aria({ "aria-disabled": "true" }, { aria: { invalid: "true" } })
65
+ # => { disabled: "true", invalid: "true" }
66
+ #
67
+ # It's designed to be used to normalize and merge aria information from system_arguments
68
+ # hashes. Consider using this pattern in component initializers:
69
+ #
70
+ # @system_arguments[:aria] = merge_aria(
71
+ # @system_arguments,
72
+ # { aria: { labelled_by: id } }
73
+ # )
74
+ def merge_aria(*hashes)
75
+ {}.tap do |result|
76
+ hashes.each do |hash|
77
+ next unless hash
78
+
79
+ result.merge!(hash.delete(:aria) || {})
80
+
81
+ hash.delete_if do |key, val|
82
+ key_s = key.to_s
83
+
84
+ if key.start_with?("aria-")
85
+ result[key_s.sub("aria-", "").to_sym] = val
86
+ true
87
+ else
88
+ false
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+
61
95
  def validate_aria_label
62
96
  aria_label = aria("label", @system_arguments)
63
97
  aria_labelledby = aria("labelledby", @system_arguments)
@@ -2,163 +2,9 @@
2
2
 
3
3
  module Primer
4
4
  module Navigation
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
- #
8
- # @accessibility
9
- # `TabComponent` renders the selected anchor tab with `aria-current="page"` by default.
10
- # When the selected tab does not correspond to the current page, such as in a nested inner tab, make sure to use aria-current="true"
11
- class TabComponent < Primer::Component
12
- DEFAULT_ARIA_CURRENT_FOR_ANCHOR = :page
13
- ARIA_CURRENT_OPTIONS_FOR_ANCHOR = [true, DEFAULT_ARIA_CURRENT_FOR_ANCHOR].freeze
14
- # Panel controlled by the Tab. This will not render anything in the tab itself.
15
- # It will provide a accessor for the Tab's parent to call and render the panel
16
- # content in the appropriate place.
17
- # Refer to `UnderlineNav` and `TabNav` implementations for examples.
18
- #
19
- # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
20
- renders_one :panel, lambda { |**system_arguments|
21
- return unless @with_panel
22
-
23
- deny_tag_argument(**system_arguments)
24
- system_arguments[:id] = @panel_id
25
- system_arguments[:tag] = :div
26
- system_arguments[:role] ||= :tabpanel
27
- system_arguments[:tabindex] = 0
28
- system_arguments[:hidden] = true unless @selected
29
-
30
- label_present = aria("label", system_arguments) || aria("labelledby", system_arguments)
31
- unless label_present
32
- if @id.present?
33
- system_arguments[:"aria-labelledby"] = @id
34
- elsif !Rails.env.production?
35
- raise ArgumentError, "Panels must be labelled. Either set a unique `id` on the tab, or set an `aria-label` directly on the panel"
36
- end
37
- end
38
-
39
- Primer::BaseComponent.new(**system_arguments)
40
- }
41
-
42
- # Icon to be rendered in the Tab left.
43
- #
44
- # @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::Beta::Octicon) %>.
45
- renders_one :icon, lambda { |icon = nil, **system_arguments|
46
- system_arguments[:classes] = class_names(
47
- @icon_classes,
48
- system_arguments[:classes]
49
- )
50
- Primer::Beta::Octicon.new(icon, **system_arguments)
51
- }
52
-
53
- # The Tab's text.
54
- #
55
- # @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::Beta::Text) %>.
56
- renders_one :text, Primer::Beta::Text
57
-
58
- # Counter to be rendered in the Tab right.
59
- #
60
- # @param kwargs [Hash] The same arguments as <%= link_to_component(Primer::Beta::Counter) %>.
61
- renders_one :counter, Primer::Beta::Counter
62
-
63
- attr_reader :selected
64
-
65
- # @example Default
66
- # <%= render(Primer::Navigation::TabComponent.new(selected: true)) do |component| %>
67
- # <% component.with_text { "Selected" } %>
68
- # <% end %>
69
- # <%= render(Primer::Navigation::TabComponent.new) do |component| %>
70
- # <% component.with_text { "Not selected" } %>
71
- # <% end %>
72
- #
73
- # @example With icons and counters
74
- # <%= render(Primer::Navigation::TabComponent.new) do |component| %>
75
- # <% component.with_icon(:star) %>
76
- # <% component.with_text { "Tab" } %>
77
- # <% end %>
78
- # <%= render(Primer::Navigation::TabComponent.new) do |component| %>
79
- # <% component.with_icon(:star) %>
80
- # <% component.with_text { "Tab" } %>
81
- # <% component.with_counter(count: 10) %>
82
- # <% end %>
83
- # <%= render(Primer::Navigation::TabComponent.new) do |component| %>
84
- # <% component.with_text { "Tab" } %>
85
- # <% component.with_counter(count: 10) %>
86
- # <% end %>
87
- #
88
- # @example Inside a list
89
- # <%= render(Primer::Navigation::TabComponent.new(list: true)) do |component| %>
90
- # <% component.with_text { "Tab" } %>
91
- # <% end %>
92
- #
93
- # @example With custom HTML
94
- # <%= render(Primer::Navigation::TabComponent.new) do %>
95
- # <div>
96
- # This is my <strong>custom HTML</strong>
97
- # </div>
98
- # <% end %>
99
- #
100
- # @param list [Boolean] Whether the Tab is an item in a `<ul>` list.
101
- # @param selected [Boolean] Whether the Tab is selected or not.
102
- # @param with_panel [Boolean] Whether the Tab has an associated panel.
103
- # @param panel_id [String] Only applies if `with_panel` is `true`. Unique id of panel.
104
- # @param icon_classes [Boolean] Classes that must always be applied to icons.
105
- # @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.
106
- # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
107
- def initialize(list: false, selected: false, with_panel: false, panel_id: "", icon_classes: "", wrapper_arguments: {}, **system_arguments)
108
- @selected = selected
109
- @icon_classes = icon_classes
110
- @list = list
111
- @with_panel = with_panel
112
-
113
- @system_arguments = system_arguments
114
- @id = @system_arguments[:id]
115
- @wrapper_arguments = wrapper_arguments
116
-
117
- if with_panel || @system_arguments[:tag] == :button
118
- @system_arguments[:tag] = :button
119
- @system_arguments[:type] = :button
120
- @system_arguments[:role] = :tab
121
- panel_id(panel_id)
122
- # https://www.w3.org/TR/wai-aria-practices/#presentation_role
123
- @wrapper_arguments[:role] = :presentation
124
- else
125
- @system_arguments[:tag] = :a
126
- end
127
-
128
- @wrapper_arguments[:tag] = :li
129
- @wrapper_arguments[:display] ||= :inline_flex
130
-
131
- return unless @selected
132
-
133
- if @system_arguments[:tag] == :a
134
- aria_current = aria("current", system_arguments) || DEFAULT_ARIA_CURRENT_FOR_ANCHOR
135
- @system_arguments[:"aria-current"] = fetch_or_fallback(ARIA_CURRENT_OPTIONS_FOR_ANCHOR, aria_current, DEFAULT_ARIA_CURRENT_FOR_ANCHOR)
136
- else
137
- @system_arguments[:"aria-selected"] = true
138
- end
139
- end
140
-
141
- def wrapper
142
- unless @list
143
- yield
144
- return # returning `yield` caused a double render
145
- end
146
-
147
- render(Primer::BaseComponent.new(**@wrapper_arguments)) do
148
- yield if block_given?
149
- end
150
- end
151
-
152
- private
153
-
154
- def panel_id(panel_id)
155
- if panel_id.blank?
156
- raise ArgumentError, "`panel_id` is required" unless Rails.env.production?
157
- else
158
- @panel_id = panel_id
159
- @system_arguments[:"aria-controls"] = @panel_id
160
- end
161
- end
5
+ # nodoc
6
+ class TabComponent < Primer::Alpha::Navigation::Tab
7
+ status :deprecated
162
8
  end
163
9
  end
164
10
  end
@@ -3,7 +3,7 @@
3
3
  module Primer
4
4
  # Use `Truncate` to shorten overflowing text with an ellipsis.
5
5
  class Truncate < Primer::Component
6
- status :beta
6
+ status :deprecated
7
7
 
8
8
  DEFAULT_TAG = :div
9
9
  TAG_OPTIONS = [DEFAULT_TAG, :span, :p, :strong].freeze
@@ -26,6 +26,15 @@ deprecations:
26
26
  autocorrect: true
27
27
  replacement: "Primer::Beta::IconButton"
28
28
 
29
+ - component: "Primer::Navigation::TabComponent"
30
+ autocorrect: true
31
+ replacement: "Primer::Alpha::Navigation::Tab"
32
+
29
33
  - component: "Primer::Tooltip"
30
34
  autocorrect: true
31
35
  replacement: "Primer::Alpha::Tooltip"
36
+
37
+ - component: "Primer::Truncate"
38
+ autocorrect: false
39
+ replacement: "Primer::Beta::Truncate"
40
+ guide: "https://primer.style/view-components/guides/primer_truncate"