openproject-primer_view_components 0.30.0 → 0.31.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -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/banner.rb +13 -13
  8. data/app/components/primer/alpha/tab_nav.css +1 -1
  9. data/app/components/primer/alpha/tab_nav.css.json +0 -2
  10. data/app/components/primer/alpha/tab_nav.css.map +1 -1
  11. data/app/components/primer/alpha/tab_nav.pcss +0 -10
  12. data/app/components/primer/alpha/tab_panels.html.erb +9 -5
  13. data/app/components/primer/alpha/tab_panels.rb +13 -4
  14. data/app/components/primer/alpha/underline_nav.css +1 -1
  15. data/app/components/primer/alpha/underline_nav.css.json +0 -2
  16. data/app/components/primer/alpha/underline_nav.css.map +1 -1
  17. data/app/components/primer/alpha/underline_nav.pcss +1 -7
  18. data/app/components/primer/alpha/underline_panels.html.erb +8 -6
  19. data/app/components/primer/alpha/underline_panels.rb +14 -6
  20. data/app/components/primer/open_project/page_header.css +1 -1
  21. data/app/components/primer/open_project/page_header.css.json +3 -1
  22. data/app/components/primer/open_project/page_header.css.map +1 -1
  23. data/app/components/primer/open_project/page_header.html.erb +1 -0
  24. data/app/components/primer/open_project/page_header.pcss +10 -0
  25. data/app/components/primer/open_project/page_header.rb +13 -0
  26. data/app/components/primer/primer.pcss +0 -1
  27. data/lib/primer/view_components/version.rb +1 -1
  28. data/previews/primer/open_project/page_header_preview/playground.html.erb +7 -0
  29. data/previews/primer/open_project/page_header_preview.rb +22 -2
  30. data/static/arguments.json +12 -0
  31. data/static/classes.json +6 -0
  32. data/static/info_arch.json +38 -1
  33. data/static/previews.json +13 -0
  34. metadata +4 -8
  35. data/app/components/primer/alpha/underline_panels.css +0 -1
  36. data/app/components/primer/alpha/underline_panels.css.json +0 -6
  37. data/app/components/primer/alpha/underline_panels.css.map +0 -1
  38. data/app/components/primer/alpha/underline_panels.pcss +0 -4
@@ -5,25 +5,25 @@ module Primer
5
5
  # Use `Banner` to highlight important information.
6
6
  #
7
7
  # @accessibility
8
- # Given that Banner is made visually prominent to sighted users through the use of icons and color, consider providing a heading and designating the Banner as a region landmark to improve navigability and discoverability of the Banner of assistive technology users. At this time, the PVC Banner does not render a heading nor render as a region landmark by default. This may be introduced in the future [as a breaking API change](https://github.com/primer/view_components/issues/2619). For now, consider providing an appropriate heading inside of the Banner and rendering the Banner as a `<section>` tag with `aria-labelledby="switch-this-with-banner-heading-id"` to implicitly designate the Banner as a region landmark.
8
+ # ### Improve discoverability with a heading and landmark
9
+ # Banners are made visually prominent with icons and colors to immediately draw attention.
9
10
  #
10
- # A Banner can be used in one of two ways – to highlight information on a page, or to communicate an urgent message/feedback for a user action. For the latter scenario, it may be necessary to use a live region or focus management technique to ensure that the Banner is discoverable and accessible for all users. Otherwise, the Banner can easily be missed, including by those using magnification software or screen reader users who may not realize that a Banner has appeared. The appropriate technique to use is highly context-dependent. Visit the [Banner's Accessibility section](https://primer.style/components/banner#accessibility) or defer to the accessibility team to determine if your scenario requires either techniques.
11
+ # To ensure the Banner is also easily discoverable for assistive technology users, consider:
12
+ # 1. Providing a heading inside of the Banner that describes the purpose of the Banner.
13
+ # 2. Designating the Banner as a `region` landmark. This can be achieved by rendering the Banner as a `section` with an `aria-labelledby` pointing to the heading.
11
14
  #
12
- # ### Announcing a Banner
13
- # When a Banner is used to communicate non-critical feedback, or is used in critical scenarios where moving focus is considered too disruptive, use a live region announcement to announce the content of the Banner to screen reader users.
15
+ # ### Communicating feedback
16
+ # When a Banner is used to communicate feedback, a live region or focus management technique should be in place to ensure that assistive technology users are aware of the feedback, especially when the Banner is shown client-side. Visit the [Banner's Accessibility section](https://primer.style/components/banner#accessibility), or defer to the accessibility team.
14
17
  #
15
- # Live regions can be finicky and don't work well when injected dynamically. Setting a live region attribute on the Banner itself is discouraged as it will not announce as expected for most screen readers.
18
+ # #### Approach 1: Announcing a Banner
19
+ # A live region announcement can be used to communicate non-critical feedback, such as a success message.
16
20
  #
17
- # To ensure a Banner is announced reliably, make sure that there's a live region container that is already on the page. When the Banner is shown, populate the live region container with the content of the Banner. This can be done in one of two ways. The first is to rely on a global live region container that is guaranteed to be on the page. When the Banner appears, populate this global live region container with the Banner content. The second technique is to hide or show the Banner within a live region wrapper that is guaranteed to always be on the page.
21
+ # To successfully trigger a live region announcement for a Banner that is un-`hidden` or dynamically injected onto the page, **do not** set the live region attribute/role on the Banner itself. Instead, it's important to rely on a live region that is already guaranteed to be on the page. Learn more about specific techniques at: [Staff only: Challenges with live regions](https://github.com/github/accessibility/blob/main/docs/coaching-recommendations/toast-flash-banner/accessible-banner-prototype.md#challenges-with-dynamically-inserted-live-region).
18
22
  #
19
- # For more information about either technique, visit [Staff only: Challenges with live regions](https://github.com/github/accessibility/blob/main/docs/coaching-recommendations/toast-flash-banner/accessible-banner-prototype.md#challenges-with-dynamically-inserted-live-region). This guidance is subject to change.
23
+ # #### Approach 2: Focusing a Banner
24
+ # Focusing the Banner can be appropriate for critical feedback scenarios, such as a [form validation error summary](https://primer.style/ui-patterns/forms/overview#interactive-summary-of-errors) where the Banner contains actions to help unblock the user.
20
25
  #
21
- # ### Focusing a Banner
22
- # Focusing a Banner when it appears helps to maximize discoverability of the message, especially in critical scenarios.
23
- #
24
- # To properly focus a banner, add a `tabindex="-1"` to the Banner container, and focus that container (one way is using the [`focus()` API](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus)).
25
- #
26
- # For more information about the focus management technique, visit the [Staff only: Accessible Banner Prototype docs](https://github.com/github/accessibility/blob/main/docs/coaching-recommendations/toast-flash-banner/accessible-banner-prototype.md#consideration). This guidance is subject to change.
26
+ # To properly focus a Banner, add a `tabindex="-1"` place focus with JavaScript (using the [`focus()` API](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus)).
27
27
  class Banner < Primer::Component
28
28
  status :alpha
29
29
 
@@ -1 +1 @@
1
- .tabnav{border-bottom:var(--borderWidth-thin) solid var(--borderColor-default);margin-bottom:var(--stack-gap-normal);margin-top:0}.tabnav-tabs{display:flex;margin-bottom:calc(var(--borderWidth-thin)*-1);overflow:auto}.tabnav::part(tablist-wrapper){border-bottom:var(--borderWidth-thin) solid var(--borderColor-default);margin-bottom:var(--stack-gap-normal)}.tabnav-tab{background-color:initial;border:var(--borderWidth-thin) solid #0000;border-bottom:0;color:var(--fgColor-muted);display:inline-block;flex-shrink:0;font-size:var(--text-body-size-medium);line-height:23px;padding:var(--base-size-8) var(--control-medium-paddingInline-spacious);-webkit-text-decoration:none;text-decoration:none;transition:color .2s cubic-bezier(.3,0,.5,1)}.tabnav-tab.selected,.tabnav-tab[aria-current]:not([aria-current=false]),.tabnav-tab[aria-selected=true]{background-color:var(--bgColor-default);border-color:var(--borderColor-default);border-radius:var(--borderRadius-medium) var(--borderRadius-medium) 0 0;color:var(--fgColor-default)}.tabnav-tab.selected .octicon,.tabnav-tab[aria-current]:not([aria-current=false]) .octicon,.tabnav-tab[aria-selected=true] .octicon{color:inherit}.tabnav-tab:hover{color:var(--fgColor-default);-webkit-text-decoration:none;text-decoration:none;transition-duration:.1s}.tabnav-tab:focus,.tabnav-tab:focus-visible{border-radius:var(--borderRadius-medium) var(--borderRadius-medium) 0 0!important;outline-offset:-6px}.tabnav-tab .octicon,.tabnav-tab:active{color:var(--fgColor-muted)}.tabnav-tab .octicon{margin-right:var(--control-small-gap)}.tabnav-tab .Counter{color:inherit;margin-left:var(--control-small-gap)}tab-container .tabnav-tab{margin-bottom:-1px}.tabnav-extra{color:var(--fgColor-muted);display:inline-block;font-size:var(--text-body-size-small);margin-left:10px;padding-top:10px}.tabnav-extra>.octicon{margin-right:2px}a.tabnav-extra:hover{color:var(--fgColor-accent);-webkit-text-decoration:none;text-decoration:none}.tabnav-btn{margin-left:var(--controlStack-medium-gap-condensed)}
1
+ .tabnav{border-bottom:var(--borderWidth-thin) solid var(--borderColor-default);margin-bottom:var(--stack-gap-normal);margin-top:0}.tabnav-tabs{display:flex;margin-bottom:calc(var(--borderWidth-thin)*-1);overflow:auto}.tabnav-tab{background-color:initial;border:var(--borderWidth-thin) solid #0000;border-bottom:0;color:var(--fgColor-muted);display:inline-block;flex-shrink:0;font-size:var(--text-body-size-medium);line-height:23px;padding:var(--base-size-8) var(--control-medium-paddingInline-spacious);-webkit-text-decoration:none;text-decoration:none;transition:color .2s cubic-bezier(.3,0,.5,1)}.tabnav-tab.selected,.tabnav-tab[aria-current]:not([aria-current=false]),.tabnav-tab[aria-selected=true]{background-color:var(--bgColor-default);border-color:var(--borderColor-default);border-radius:var(--borderRadius-medium) var(--borderRadius-medium) 0 0;color:var(--fgColor-default)}.tabnav-tab.selected .octicon,.tabnav-tab[aria-current]:not([aria-current=false]) .octicon,.tabnav-tab[aria-selected=true] .octicon{color:inherit}.tabnav-tab:hover{color:var(--fgColor-default);-webkit-text-decoration:none;text-decoration:none;transition-duration:.1s}.tabnav-tab:focus,.tabnav-tab:focus-visible{border-radius:var(--borderRadius-medium) var(--borderRadius-medium) 0 0!important;outline-offset:-6px}.tabnav-tab .octicon,.tabnav-tab:active{color:var(--fgColor-muted)}.tabnav-tab .octicon{margin-right:var(--control-small-gap)}.tabnav-tab .Counter{color:inherit;margin-left:var(--control-small-gap)}.tabnav-extra{color:var(--fgColor-muted);display:inline-block;font-size:var(--text-body-size-small);margin-left:10px;padding-top:10px}.tabnav-extra>.octicon{margin-right:2px}a.tabnav-extra:hover{color:var(--fgColor-accent);-webkit-text-decoration:none;text-decoration:none}.tabnav-btn{margin-left:var(--controlStack-medium-gap-condensed)}
@@ -3,7 +3,6 @@
3
3
  "selectors": [
4
4
  ".tabnav",
5
5
  ".tabnav-tabs",
6
- ".tabnav::part(tablist-wrapper)",
7
6
  ".tabnav-tab",
8
7
  ".tabnav-tab.selected",
9
8
  ".tabnav-tab[aria-current]:not([aria-current=false])",
@@ -17,7 +16,6 @@
17
16
  ".tabnav-tab .octicon",
18
17
  ".tabnav-tab:active",
19
18
  ".tabnav-tab .Counter",
20
- "tab-container .tabnav-tab",
21
19
  ".tabnav-extra",
22
20
  ".tabnav-extra>.octicon",
23
21
  "a.tabnav-extra:hover",
@@ -1 +1 @@
1
- {"version":3,"sources":["tab_nav.pcss"],"names":[],"mappings":"AAGA,QAGE,sEAAuE,CADvE,qCAAsC,CADtC,YAGF,CAEA,aACE,YAAa,CACb,8CAAiD,CACjD,aACF,CAEA,+BAEE,sEAAuE,CADvE,qCAEF,CAEA,YAQE,wBAA6B,CAE7B,0CAAgB,CAAhB,eAAgB,CAJhB,0BAA2B,CAL3B,oBAAqB,CACrB,aAAc,CAEd,sCAAuC,CACvC,gBAAiB,CAFjB,uEAAwE,CAIxE,4BAAqB,CAArB,oBAAqB,CAIrB,4CAwCF,CAtCE,yGAIE,uCAAwC,CACxC,uCAAwC,CACxC,uEAAwE,CAHxE,4BAQF,CAHE,oIACE,aACF,CAGF,kBACE,4BAA6B,CAC7B,4BAAqB,CAArB,oBAAqB,CACrB,uBACF,CAEA,4CAEE,iFAAmF,CACnF,mBACF,CAMA,wCAHE,0BAMF,CAHA,qBACE,qCAEF,CAEA,qBAEE,aAAc,CADd,oCAEF,CAGF,0BACE,kBACF,CAQA,cAKE,0BAA2B,CAJ3B,oBAAqB,CAGrB,qCAAsC,CADtC,gBAAiB,CADjB,gBAQF,CAHE,uBACE,gBACF,CAKF,qBACE,2BAA4B,CAC5B,4BAAqB,CAArB,oBACF,CAOA,YACE,oDACF","file":"tab_nav.css","sourcesContent":["/* tabnav */\n\n/* Outer wrapper */\n.tabnav {\n margin-top: 0;\n margin-bottom: var(--stack-gap-normal);\n border-bottom: var(--borderWidth-thin) solid var(--borderColor-default);\n}\n\n.tabnav-tabs {\n display: flex;\n margin-bottom: calc(var(--borderWidth-thin) * -1);\n overflow: auto;\n}\n\n.tabnav::part(tablist-wrapper) {\n margin-bottom: var(--stack-gap-normal);\n border-bottom: var(--borderWidth-thin) solid var(--borderColor-default);\n}\n\n.tabnav-tab {\n display: inline-block;\n flex-shrink: 0;\n padding: var(--base-size-8) var(--control-medium-paddingInline-spacious);\n font-size: var(--text-body-size-medium);\n line-height: 23px;\n color: var(--fgColor-muted);\n text-decoration: none;\n background-color: transparent;\n border: var(--borderWidth-thin) solid transparent;\n border-bottom: 0;\n transition: color 0.2s cubic-bezier(0.3, 0, 0.5, 1);\n\n &.selected,\n &[aria-selected='true'],\n &[aria-current]:not([aria-current='false']) {\n color: var(--fgColor-default);\n background-color: var(--bgColor-default); /* cover bottom border */\n border-color: var(--borderColor-default);\n border-radius: var(--borderRadius-medium) var(--borderRadius-medium) 0 0;\n\n & .octicon {\n color: inherit;\n }\n }\n\n &:hover {\n color: var(--fgColor-default);\n text-decoration: none;\n transition-duration: 0.1s;\n }\n\n &:focus,\n &:focus-visible {\n border-radius: var(--borderRadius-medium) var(--borderRadius-medium) 0 0 !important;\n outline-offset: -6px;\n }\n\n &:active {\n color: var(--fgColor-muted);\n }\n\n & .octicon {\n margin-right: var(--control-small-gap);\n color: var(--fgColor-muted);\n }\n\n & .Counter {\n margin-left: var(--control-small-gap);\n color: inherit;\n }\n}\n\ntab-container .tabnav-tab {\n margin-bottom: -1px;\n}\n\n\n/* Tabnav extras\n**\n** Tabnav extras are non-tab elements that sit in the tabnav. Usually they're\n** inline text or links. */\n\n.tabnav-extra {\n display: inline-block;\n padding-top: 10px;\n margin-left: 10px;\n font-size: var(--text-body-size-small);\n color: var(--fgColor-muted);\n\n & > .octicon {\n margin-right: 2px;\n }\n}\n\n/* When tabnav-extra are anchors\n** stylelint-disable-next-line selector-no-qualifying-type */\na.tabnav-extra:hover {\n color: var(--fgColor-accent);\n text-decoration: none;\n}\n\n/* Tabnav buttons\n**\n** For when there are multiple buttons, space them out appropriately. Requires\n** the buttons to be floated or inline-block. */\n\n.tabnav-btn {\n margin-left: var(--controlStack-medium-gap-condensed);\n}\n"]}
1
+ {"version":3,"sources":["tab_nav.pcss"],"names":[],"mappings":"AAGA,QAGE,sEAAuE,CADvE,qCAAsC,CADtC,YAGF,CAEA,aACE,YAAa,CACb,8CAAiD,CACjD,aACF,CAEA,YAQE,wBAA6B,CAE7B,0CAAgB,CAAhB,eAAgB,CAJhB,0BAA2B,CAL3B,oBAAqB,CACrB,aAAc,CAEd,sCAAuC,CACvC,gBAAiB,CAFjB,uEAAwE,CAIxE,4BAAqB,CAArB,oBAAqB,CAIrB,4CAwCF,CAtCE,yGAIE,uCAAwC,CACxC,uCAAwC,CACxC,uEAAwE,CAHxE,4BAQF,CAHE,oIACE,aACF,CAGF,kBACE,4BAA6B,CAC7B,4BAAqB,CAArB,oBAAqB,CACrB,uBACF,CAEA,4CAEE,iFAAmF,CACnF,mBACF,CAMA,wCAHE,0BAMF,CAHA,qBACE,qCAEF,CAEA,qBAEE,aAAc,CADd,oCAEF,CAQF,cAKE,0BAA2B,CAJ3B,oBAAqB,CAGrB,qCAAsC,CADtC,gBAAiB,CADjB,gBAQF,CAHE,uBACE,gBACF,CAKF,qBACE,2BAA4B,CAC5B,4BAAqB,CAArB,oBACF,CAOA,YACE,oDACF","file":"tab_nav.css","sourcesContent":["/* tabnav */\n\n/* Outer wrapper */\n.tabnav {\n margin-top: 0;\n margin-bottom: var(--stack-gap-normal);\n border-bottom: var(--borderWidth-thin) solid var(--borderColor-default);\n}\n\n.tabnav-tabs {\n display: flex;\n margin-bottom: calc(var(--borderWidth-thin) * -1);\n overflow: auto;\n}\n\n.tabnav-tab {\n display: inline-block;\n flex-shrink: 0;\n padding: var(--base-size-8) var(--control-medium-paddingInline-spacious);\n font-size: var(--text-body-size-medium);\n line-height: 23px;\n color: var(--fgColor-muted);\n text-decoration: none;\n background-color: transparent;\n border: var(--borderWidth-thin) solid transparent;\n border-bottom: 0;\n transition: color 0.2s cubic-bezier(0.3, 0, 0.5, 1);\n\n &.selected,\n &[aria-selected='true'],\n &[aria-current]:not([aria-current='false']) {\n color: var(--fgColor-default);\n background-color: var(--bgColor-default); /* cover bottom border */\n border-color: var(--borderColor-default);\n border-radius: var(--borderRadius-medium) var(--borderRadius-medium) 0 0;\n\n & .octicon {\n color: inherit;\n }\n }\n\n &:hover {\n color: var(--fgColor-default);\n text-decoration: none;\n transition-duration: 0.1s;\n }\n\n &:focus,\n &:focus-visible {\n border-radius: var(--borderRadius-medium) var(--borderRadius-medium) 0 0 !important;\n outline-offset: -6px;\n }\n\n &:active {\n color: var(--fgColor-muted);\n }\n\n & .octicon {\n margin-right: var(--control-small-gap);\n color: var(--fgColor-muted);\n }\n\n & .Counter {\n margin-left: var(--control-small-gap);\n color: inherit;\n }\n}\n\n/* Tabnav extras\n**\n** Tabnav extras are non-tab elements that sit in the tabnav. Usually they're\n** inline text or links. */\n\n.tabnav-extra {\n display: inline-block;\n padding-top: 10px;\n margin-left: 10px;\n font-size: var(--text-body-size-small);\n color: var(--fgColor-muted);\n\n & > .octicon {\n margin-right: 2px;\n }\n}\n\n/* When tabnav-extra are anchors\n** stylelint-disable-next-line selector-no-qualifying-type */\na.tabnav-extra:hover {\n color: var(--fgColor-accent);\n text-decoration: none;\n}\n\n/* Tabnav buttons\n**\n** For when there are multiple buttons, space them out appropriately. Requires\n** the buttons to be floated or inline-block. */\n\n.tabnav-btn {\n margin-left: var(--controlStack-medium-gap-condensed);\n}\n"]}
@@ -13,11 +13,6 @@
13
13
  overflow: auto;
14
14
  }
15
15
 
16
- .tabnav::part(tablist-wrapper) {
17
- margin-bottom: var(--stack-gap-normal);
18
- border-bottom: var(--borderWidth-thin) solid var(--borderColor-default);
19
- }
20
-
21
16
  .tabnav-tab {
22
17
  display: inline-block;
23
18
  flex-shrink: 0;
@@ -71,11 +66,6 @@
71
66
  }
72
67
  }
73
68
 
74
- tab-container .tabnav-tab {
75
- margin-bottom: -1px;
76
- }
77
-
78
-
79
69
  /* Tabnav extras
80
70
  **
81
71
  ** Tabnav extras are non-tab elements that sit in the tabnav. Usually they're
@@ -1,9 +1,13 @@
1
- <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
- <%= extra if @align == :left %>
3
- <% tabs.each do |tab| %>
4
- <%= tab %>
1
+ <%= tab_container_wrapper(with_panel: true, **@wrapper_arguments) do %>
2
+ <%= render Primer::BaseComponent.new(**@system_arguments) do %>
3
+ <%= extra if @align == :left %>
4
+ <%= render Primer::BaseComponent.new(**@body_arguments) do %>
5
+ <% tabs.each do |tab| %>
6
+ <%= tab %>
7
+ <% end %>
8
+ <% end %>
9
+ <%= extra if @align == :right %>
5
10
  <% end %>
6
- <%= extra if @align == :right %>
7
11
  <% tabs.each do |tab| %>
8
12
  <%= tab.panel %>
9
13
  <% end %>
@@ -26,7 +26,7 @@ module Primer
26
26
  Primer::Alpha::Navigation::Tab.new(
27
27
  selected: selected,
28
28
  with_panel: true,
29
- list: false,
29
+ list: true,
30
30
  panel_id: "panel-#{id}",
31
31
  **system_arguments
32
32
  )
@@ -43,14 +43,23 @@ module Primer
43
43
 
44
44
  # @param label [String] Sets an `aria-label` that helps assistive technology users understand the purpose of the tabs.
45
45
  # @param align [Symbol] <%= one_of(Primer::TabNavHelper::EXTRA_ALIGN_OPTIONS) %> - Defaults to <%= Primer::TabNavHelper::EXTRA_ALIGN_DEFAULT %>
46
+ # @param body_arguments [Hash] <%= link_to_system_arguments_docs %> for the body wrapper.
47
+ # @param wrapper_arguments [Hash] <%= link_to_system_arguments_docs %> for the `TabContainer` wrapper.
46
48
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
47
49
  def initialize(label:, body_arguments: {}, wrapper_arguments: {}, **system_arguments)
48
50
  @align = EXTRA_ALIGN_DEFAULT
51
+ @wrapper_arguments = wrapper_arguments
49
52
 
50
- @system_arguments = { **deny_tag_argument(**system_arguments), **deny_tag_argument(**wrapper_arguments) }
51
- @system_arguments[:tag] = :"tab-container"
53
+ @system_arguments = deny_tag_argument(**system_arguments)
54
+ @system_arguments[:tag] = :div
52
55
  @system_arguments[:classes] = tab_nav_classes(@system_arguments[:classes])
53
- @system_arguments[:"aria-label"] = label
56
+
57
+ @body_arguments = deny_tag_argument(**body_arguments)
58
+ @body_arguments[:tag] = :ul
59
+ @body_arguments[:classes] = tab_nav_body_classes(@body_arguments[:classes])
60
+
61
+ @body_arguments[:role] = :tablist
62
+ @body_arguments[:"aria-label"] = label
54
63
  end
55
64
 
56
65
  def before_render
@@ -1 +1 @@
1
- .UnderlineNav{box-shadow:inset 0 -1px 0 var(--borderColor-muted);display:flex;min-height:var(--base-size-48);overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:auto;justify-content:space-between}.UnderlineNav .Counter{background-color:var(--bgColor-neutral-muted,var(--color-neutral-muted));color:var(--fgColor-default);margin-left:var(--control-medium-gap)}.UnderlineNav .Counter--primary{background-color:var(--bgColor-neutral-emphasis);color:var(--fgColor-onEmphasis)}.UnderlineNav::part(tablist-wrapper){box-shadow:inset 0 -1px 0 var(--borderColor-muted);padding:var(--control-medium-gap) 0;width:100%}.UnderlineNav-body,.UnderlineNav::part(tablist){align-items:center;display:flex;gap:var(--control-medium-gap);list-style:none}.UnderlineNav-item{align-items:center;background-color:initial;border:0;border-radius:var(--borderRadius-medium);color:var(--fgColor-default);cursor:pointer;display:flex;font-size:var(--text-body-size-medium);line-height:30px;padding:0 var(--control-medium-paddingInline-condensed);position:relative;text-align:center;white-space:nowrap}.UnderlineNav-item:focus,.UnderlineNav-item:focus-visible,.UnderlineNav-item:hover{border-bottom-color:var(--borderColor-neutral-muted);color:var(--fgColor-default);outline-offset:-2px;-webkit-text-decoration:none;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);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(--control-transparent-bgColor-hover);color:var(--fgColor-default);-webkit-text-decoration:none;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(--underlineNav-borderColor-active);color:var(--fgColor-default);font-weight:var(--base-text-weight-semibold)}.UnderlineNav-item.selected:after,.UnderlineNav-item[aria-current]:not([aria-current=false]):after,.UnderlineNav-item[role=tab][aria-selected=true]:after{background:var(--underlineNav-borderColor-active);border-radius:var(--borderRadius-medium);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)}.UnderlineNav-octicon{color:var(--fgColor-muted);display:inline!important;margin-right:var(--control-medium-gap);fill:var(--fgColor-muted)}.UnderlineNav-container{display:flex;justify-content:space-between}
1
+ .UnderlineNav{box-shadow:inset 0 -1px 0 var(--borderColor-muted);display:flex;min-height:var(--base-size-48);overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:auto;justify-content:space-between}.UnderlineNav .Counter{background-color:var(--bgColor-neutral-muted,var(--color-neutral-muted));color:var(--fgColor-default);margin-left:var(--control-medium-gap)}.UnderlineNav .Counter--primary{background-color:var(--bgColor-neutral-emphasis);color:var(--fgColor-onEmphasis)}.UnderlineNav-body{align-items:center;display:flex;gap:var(--control-medium-gap);list-style:none}.UnderlineNav-item{align-items:center;background-color:initial;border:0;border-radius:var(--borderRadius-medium);color:var(--fgColor-default);cursor:pointer;display:flex;font-size:var(--text-body-size-medium);line-height:30px;padding:0 var(--control-medium-paddingInline-condensed);position:relative;text-align:center;white-space:nowrap}.UnderlineNav-item:focus,.UnderlineNav-item:focus-visible,.UnderlineNav-item:hover{border-bottom-color:var(--borderColor-neutral-muted);color:var(--fgColor-default);outline-offset:-2px;-webkit-text-decoration:none;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);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(--control-transparent-bgColor-hover);color:var(--fgColor-default);-webkit-text-decoration:none;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(--underlineNav-borderColor-active);color:var(--fgColor-default);font-weight:var(--base-text-weight-semibold)}.UnderlineNav-item.selected:after,.UnderlineNav-item[aria-current]:not([aria-current=false]):after,.UnderlineNav-item[role=tab][aria-selected=true]:after{background:var(--underlineNav-borderColor-active);border-radius:var(--borderRadius-medium);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)}.UnderlineNav-octicon{color:var(--fgColor-muted);display:inline!important;margin-right:var(--control-medium-gap);fill:var(--fgColor-muted)}.UnderlineNav-container{display:flex;justify-content:space-between}
@@ -4,9 +4,7 @@
4
4
  ".UnderlineNav",
5
5
  ".UnderlineNav .Counter",
6
6
  ".UnderlineNav .Counter--primary",
7
- ".UnderlineNav::part(tablist-wrapper)",
8
7
  ".UnderlineNav-body",
9
- ".UnderlineNav::part(tablist)",
10
8
  ".UnderlineNav-item",
11
9
  ".UnderlineNav-item:focus",
12
10
  ".UnderlineNav-item:focus-visible",
@@ -1 +1 @@
1
- {"version":3,"sources":["underline_nav.pcss","<no source>"],"names":[],"mappings":"AAEA,cAKE,kDAAmD,CAJnD,YAAa,CACb,8BAA+B,CAC/B,eAAgB,CAChB,iBAAkB,CAElB,+BAAgC,CAChC,6BAYF,CAVE,uBAGE,wEAA0E,CAD1E,4BAA6B,CAD7B,qCAGF,CAEA,gCAEE,gDAAiD,CADjD,+BAEF,CAGF,qCAEE,kDAAmD,CACnD,mCAAoC,CAFpC,UAGF,CAEA,gDAEE,kBAAmB,CADnB,YAAa,CAEb,6BAA8B,CAC9B,eACF,CAEA,mBAaE,kBAAmB,CAHnB,wBAA6B,CAC7B,QAAS,CACT,wCAAyC,CANzC,4BAA6B,CAG7B,cAAe,CAPf,YAAa,CAEb,sCAAuC,CACvC,gBAAiB,CAFjB,uDAAwD,CAFxD,iBAAkB,CAMlB,iBAAkB,CAClB,kBA8DF,CAvDE,mFAKE,oDAAqD,CAFrD,4BAA6B,CAG7B,mBAAoB,CAFpB,4BAAqB,CAArB,oBAAqB,CAGrB,4CACF,CAGA,yCAKE,0BAA2B,CAJ3B,aAAc,CAEd,4CAA6C,CAD7C,QAAS,CAET,iBAEF,CAIE,0BCxEJ,WAAA,YAAA,SAAA,gBAAA,kBAAA,QAAA,4CAAA,UDwE8B,CAI5B,sBACE,yBAGE,mDAAoD,CAFpD,4BAA6B,CAC7B,4BAAqB,CAArB,oBAAqB,CAErB,mCACF,CACF,CAEA,wIAKE,0DAA2D,CAD3D,4BAA6B,CAD7B,4CAiBF,CAZE,0JAQE,iDAAkD,CAClD,wCAAyC,CALzC,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,8BACF,CAGF,sBAGE,0BAA2B,CAF3B,wBAA0B,CAC1B,sCAAuC,CAEvC,yBACF,CAEA,wBACE,YAAa,CACb,6BACF","file":"underline_nav.css","sourcesContent":["/* UnderlineNav */\n\n.UnderlineNav {\n display: flex;\n min-height: var(--base-size-48);\n overflow-x: auto;\n overflow-y: hidden;\n box-shadow: inset 0 -1px 0 var(--borderColor-muted);\n -webkit-overflow-scrolling: auto;\n justify-content: space-between;\n\n & .Counter {\n margin-left: var(--control-medium-gap);\n color: var(--fgColor-default);\n background-color: var(--bgColor-neutral-muted, var(--color-neutral-muted));\n }\n\n & .Counter--primary {\n color: var(--fgColor-onEmphasis);\n background-color: var(--bgColor-neutral-emphasis);\n }\n}\n\n.UnderlineNav::part(tablist-wrapper) {\n width: 100%;\n box-shadow: inset 0 -1px 0 var(--borderColor-muted);\n padding: var(--control-medium-gap) 0;\n}\n\n.UnderlineNav-body,.UnderlineNav::part(tablist) {\n display: flex;\n align-items: center;\n gap: var(--control-medium-gap);\n list-style: none;\n}\n\n.UnderlineNav-item {\n position: relative;\n display: flex;\n padding: 0 var(--control-medium-paddingInline-condensed);\n font-size: var(--text-body-size-medium);\n line-height: 30px;\n color: var(--fgColor-default);\n text-align: center;\n white-space: nowrap;\n cursor: pointer;\n background-color: transparent;\n border: 0;\n border-radius: var(--borderRadius-medium);\n align-items: center;\n\n &:hover,\n &:focus,\n &:focus-visible {\n color: var(--fgColor-default);\n text-decoration: none;\n border-bottom-color: var(--borderColor-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);\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(--fgColor-default);\n text-decoration: none;\n background: var(--control-transparent-bgColor-hover);\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);\n color: var(--fgColor-default);\n border-bottom-color: var(--underlineNav-borderColor-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(--underlineNav-borderColor-active);\n border-radius: var(--borderRadius-medium);\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);\n }\n}\n\n.UnderlineNav-octicon {\n display: inline !important;\n margin-right: var(--control-medium-gap);\n color: var(--fgColor-muted);\n fill: var(--fgColor-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,cAKE,kDAAmD,CAJnD,YAAa,CACb,8BAA+B,CAC/B,eAAgB,CAChB,iBAAkB,CAElB,+BAAgC,CAChC,6BAYF,CAVE,uBAGE,wEAA0E,CAD1E,4BAA6B,CAD7B,qCAGF,CAEA,gCAEE,gDAAiD,CADjD,+BAEF,CAGF,mBAEE,kBAAmB,CADnB,YAAa,CAEb,6BAA8B,CAC9B,eACF,CAEA,mBAaE,kBAAmB,CAHnB,wBAA6B,CAC7B,QAAS,CACT,wCAAyC,CANzC,4BAA6B,CAG7B,cAAe,CAPf,YAAa,CAEb,sCAAuC,CACvC,gBAAiB,CAFjB,uDAAwD,CAFxD,iBAAkB,CAMlB,iBAAkB,CAClB,kBA8DF,CAvDE,mFAKE,oDAAqD,CAFrD,4BAA6B,CAG7B,mBAAoB,CAFpB,4BAAqB,CAArB,oBAAqB,CAGrB,4CACF,CAGA,yCAKE,0BAA2B,CAJ3B,aAAc,CAEd,4CAA6C,CAD7C,QAAS,CAET,iBAEF,CAIE,0BClEJ,WAAA,YAAA,SAAA,gBAAA,kBAAA,QAAA,4CAAA,UDkE8B,CAI5B,sBACE,yBAGE,mDAAoD,CAFpD,4BAA6B,CAC7B,4BAAqB,CAArB,oBAAqB,CAErB,mCACF,CACF,CAEA,wIAKE,0DAA2D,CAD3D,4BAA6B,CAD7B,4CAiBF,CAZE,0JAQE,iDAAkD,CAClD,wCAAyC,CALzC,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,8BACF,CAGF,sBAGE,0BAA2B,CAF3B,wBAA0B,CAC1B,sCAAuC,CAEvC,yBACF,CAEA,wBACE,YAAa,CACb,6BACF","file":"underline_nav.css","sourcesContent":["/* UnderlineNav */\n\n.UnderlineNav {\n display: flex;\n min-height: var(--base-size-48);\n overflow-x: auto;\n overflow-y: hidden;\n box-shadow: inset 0 -1px 0 var(--borderColor-muted);\n -webkit-overflow-scrolling: auto;\n justify-content: space-between;\n\n & .Counter {\n margin-left: var(--control-medium-gap);\n color: var(--fgColor-default);\n background-color: var(--bgColor-neutral-muted, var(--color-neutral-muted));\n }\n\n & .Counter--primary {\n color: var(--fgColor-onEmphasis);\n background-color: var(--bgColor-neutral-emphasis);\n }\n}\n\n.UnderlineNav-body {\n display: flex;\n align-items: center;\n gap: var(--control-medium-gap);\n list-style: none;\n}\n\n.UnderlineNav-item {\n position: relative;\n display: flex;\n padding: 0 var(--control-medium-paddingInline-condensed);\n font-size: var(--text-body-size-medium);\n line-height: 30px;\n color: var(--fgColor-default);\n text-align: center;\n white-space: nowrap;\n cursor: pointer;\n background-color: transparent;\n border: 0;\n border-radius: var(--borderRadius-medium);\n align-items: center;\n\n &:hover,\n &:focus,\n &:focus-visible {\n color: var(--fgColor-default);\n text-decoration: none;\n border-bottom-color: var(--borderColor-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);\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(--fgColor-default);\n text-decoration: none;\n background: var(--control-transparent-bgColor-hover);\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);\n color: var(--fgColor-default);\n border-bottom-color: var(--underlineNav-borderColor-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(--underlineNav-borderColor-active);\n border-radius: var(--borderRadius-medium);\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);\n }\n}\n\n.UnderlineNav-octicon {\n display: inline !important;\n margin-right: var(--control-medium-gap);\n color: var(--fgColor-muted);\n fill: var(--fgColor-muted);\n}\n\n.UnderlineNav-container {\n display: flex;\n justify-content: space-between;\n}\n",null]}
@@ -21,13 +21,7 @@
21
21
  }
22
22
  }
23
23
 
24
- .UnderlineNav::part(tablist-wrapper) {
25
- width: 100%;
26
- box-shadow: inset 0 -1px 0 var(--borderColor-muted);
27
- padding: var(--control-medium-gap) 0;
28
- }
29
-
30
- .UnderlineNav-body,.UnderlineNav::part(tablist) {
24
+ .UnderlineNav-body {
31
25
  display: flex;
32
26
  align-items: center;
33
27
  gap: var(--control-medium-gap);
@@ -1,16 +1,18 @@
1
- <%= render Primer::BaseComponent.new(**@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
- <% tabs.each do |tab| %>
7
- <%= tab %>
6
+ <%= render body do %>
7
+ <% tabs.each do |tab| %>
8
+ <%= tab %>
9
+ <% end %>
8
10
  <% end %>
9
11
  <% if @align == :left %>
10
12
  <%= actions %>
11
13
  <% end %>
12
- <% tabs.each do |tab| %>
13
- <%= tab.panel %>
14
- <% end %>
14
+ <% end %>
15
+ <% tabs.each do |tab| %>
16
+ <%= tab.panel %>
15
17
  <% end %>
16
18
  <% end %>
@@ -18,7 +18,7 @@ module Primer
18
18
  Primer::Alpha::Navigation::Tab.new(
19
19
  selected: selected,
20
20
  with_panel: true,
21
- list: false,
21
+ list: true,
22
22
  icon_classes: "UnderlineNav-octicon",
23
23
  panel_id: "panel-#{id}",
24
24
  **system_arguments
@@ -43,16 +43,24 @@ module Primer
43
43
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
44
44
  def initialize(label:, align: ALIGN_DEFAULT, body_arguments: {}, wrapper_arguments: {}, **system_arguments)
45
45
  @align = fetch_or_fallback(ALIGN_OPTIONS, align, ALIGN_DEFAULT)
46
- @wrapper_arguments = deny_tag_argument(**wrapper_arguments)
47
- @wrapper_arguments[:tag] = :div
46
+ @wrapper_arguments = wrapper_arguments
48
47
 
49
48
  @system_arguments = deny_tag_argument(**system_arguments)
50
- @system_arguments[:tag] = :"tab-container"
49
+ @system_arguments[:tag] = :div
51
50
  @system_arguments[:classes] = underline_nav_classes(@system_arguments[:classes], @align)
52
- @system_arguments[:"aria-label"] = label
53
51
 
54
52
  @body_arguments = deny_tag_argument(**body_arguments)
55
- @body_arguments[:tag] = :div
53
+ @body_arguments[:tag] = :ul
54
+ @body_arguments[:classes] = underline_nav_body_classes(@body_arguments[:classes])
55
+
56
+ @body_arguments[:role] = :tablist
57
+ @body_arguments[:"aria-label"] = label
58
+ end
59
+
60
+ private
61
+
62
+ def body
63
+ Primer::BaseComponent.new(**@body_arguments)
56
64
  end
57
65
  end
58
66
  end
@@ -1 +1 @@
1
- .PageHeader{border-bottom:var(--borderWidth-thin) solid var(--borderColor-muted);display:flex;flex-flow:column;margin-bottom:var(--stack-gap-normal);padding-bottom:var(--stack-padding-condensed)}.PageHeader-contextBar{margin-bottom:var(--base-size-8)}.PageHeader-contextBar,.PageHeader-titleBar{align-items:center;display:flex;flex-flow:row;justify-content:flex-end}.PageHeader-titleBar{margin-bottom:var(--space-xsmall)}.PageHeader-title{flex:1 1 auto;font-size:var(--text-title-size-medium);font-weight:var(--base-text-weight-normal)}.PageHeader-title--large{font-size:var(--text-title-size-large)}.PageHeader-description{color:var(--fgColor-muted);flex:1 100%;font-size:var(--text-body-size-medium)}.PageHeader-actions{align-items:center;display:flex;justify-content:flex-end}.PageHeader-breadcrumbs{display:block;width:100%}.PageHeader-leadingAction{margin-right:var(--base-size-4);margin-top:2px}.PageHeader-parentLink{flex:1 1 auto}
1
+ .PageHeader{border-bottom:var(--borderWidth-thin) solid var(--borderColor-muted);display:flex;flex-flow:column;margin-bottom:var(--stack-gap-normal);padding-bottom:var(--stack-padding-condensed)}.PageHeader--noBorder{border-bottom:none;padding-bottom:0}.PageHeader-contextBar{margin-bottom:var(--base-size-8)}.PageHeader-contextBar,.PageHeader-titleBar{align-items:center;display:flex;flex-flow:row;justify-content:flex-end}.PageHeader-titleBar{margin-bottom:var(--space-xsmall)}.PageHeader-title{flex:1 1 auto;font-size:var(--text-title-size-medium);font-weight:var(--base-text-weight-normal)}.PageHeader-title--large{font-size:var(--text-title-size-large)}.PageHeader-description{color:var(--fgColor-muted);flex:1 100%;font-size:var(--text-body-size-medium)}.PageHeader-actions{align-items:center;display:flex;justify-content:flex-end}.PageHeader-breadcrumbs{display:block;width:100%}.PageHeader-leadingAction{margin-right:var(--base-size-4);margin-top:2px}.PageHeader-parentLink{flex:1 1 auto}.PageHeader-tabNav{margin-bottom:0;margin-top:var(--stack-gap-normal)}
@@ -2,6 +2,7 @@
2
2
  "name": "open_project/page_header",
3
3
  "selectors": [
4
4
  ".PageHeader",
5
+ ".PageHeader--noBorder",
5
6
  ".PageHeader-contextBar",
6
7
  ".PageHeader-titleBar",
7
8
  ".PageHeader-title",
@@ -10,6 +11,7 @@
10
11
  ".PageHeader-actions",
11
12
  ".PageHeader-breadcrumbs",
12
13
  ".PageHeader-leadingAction",
13
- ".PageHeader-parentLink"
14
+ ".PageHeader-parentLink",
15
+ ".PageHeader-tabNav"
14
16
  ]
15
17
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["page_header.pcss"],"names":[],"mappings":"AAEA,YAIE,oEAAqE,CAHrE,YAAa,CAIb,gBAAiB,CAFjB,qCAAsC,CADtC,6CAIF,CAEA,uBAKE,gCACF,CAEA,4CAJE,kBAAmB,CAHnB,YAAa,CACb,aAAc,CACd,wBAWF,CANA,qBAKE,iCACF,CAEA,kBAGE,aAAc,CAFd,uCAAwC,CACxC,0CAEF,CAEA,yBACE,sCACF,CAGA,wBAEE,0BAA2B,CAC3B,WAAY,CAFZ,sCAGF,CAEA,oBAGE,kBAAmB,CADnB,YAAa,CADb,wBAGF,CAEA,wBACE,aAAc,CACd,UACF,CAEA,0BAEE,+BAAgC,CADhC,cAEF,CAEA,uBACE,aACF","file":"page_header.css","sourcesContent":["/* OP PageHeader */\n\n.PageHeader {\n display: flex;\n padding-bottom: var(--stack-padding-condensed);\n margin-bottom: var(--stack-gap-normal);\n border-bottom: var(--borderWidth-thin) solid var(--borderColor-muted);\n flex-flow: column;\n}\n\n.PageHeader-contextBar {\n display: flex;\n flex-flow: row;\n justify-content: flex-end;\n align-items: center;\n margin-bottom: var(--base-size-8);\n}\n\n.PageHeader-titleBar {\n display: flex;\n flex-flow: row;\n justify-content: flex-end;\n align-items: center; /* Keep back button vertically aligned. */\n margin-bottom: var(--space-xsmall);\n}\n\n.PageHeader-title {\n font-size: var(--text-title-size-medium);\n font-weight: var(--base-text-weight-normal);\n flex: 1 1 auto;\n}\n\n.PageHeader-title--large {\n font-size: var(--text-title-size-large);\n}\n\n/* One-liner of supporting text */\n.PageHeader-description {\n font-size: var(--text-body-size-medium);\n color: var(--fgColor-muted);\n flex: 1 100%;\n}\n\n.PageHeader-actions {\n justify-content: flex-end;\n display: flex;\n align-items: center;\n}\n\n.PageHeader-breadcrumbs {\n display: block;\n width: 100%;\n}\n\n.PageHeader-leadingAction {\n margin-top: 2px; /* to center align with label */\n margin-right: var(--base-size-4);\n}\n\n.PageHeader-parentLink {\n flex: 1 1 auto;\n}\n"]}
1
+ {"version":3,"sources":["page_header.pcss"],"names":[],"mappings":"AAEA,YAIE,oEAAqE,CAHrE,YAAa,CAIb,gBAAiB,CAFjB,qCAAsC,CADtC,6CAIF,CAEA,sBACE,kBAAmB,CACnB,gBACF,CAEA,uBAKE,gCACF,CAEA,4CAJE,kBAAmB,CAHnB,YAAa,CACb,aAAc,CACd,wBAWF,CANA,qBAKE,iCACF,CAEA,kBAGE,aAAc,CAFd,uCAAwC,CACxC,0CAEF,CAEA,yBACE,sCACF,CAGA,wBAEE,0BAA2B,CAC3B,WAAY,CAFZ,sCAGF,CAEA,oBAGE,kBAAmB,CADnB,YAAa,CADb,wBAGF,CAEA,wBACE,aAAc,CACd,UACF,CAEA,0BAEE,+BAAgC,CADhC,cAEF,CAEA,uBACE,aACF,CAEA,mBAEE,eAAgB,CADhB,kCAEF","file":"page_header.css","sourcesContent":["/* OP PageHeader */\n\n.PageHeader {\n display: flex;\n padding-bottom: var(--stack-padding-condensed);\n margin-bottom: var(--stack-gap-normal);\n border-bottom: var(--borderWidth-thin) solid var(--borderColor-muted);\n flex-flow: column;\n}\n\n.PageHeader--noBorder {\n border-bottom: none;\n padding-bottom: 0;\n}\n\n.PageHeader-contextBar {\n display: flex;\n flex-flow: row;\n justify-content: flex-end;\n align-items: center;\n margin-bottom: var(--base-size-8);\n}\n\n.PageHeader-titleBar {\n display: flex;\n flex-flow: row;\n justify-content: flex-end;\n align-items: center; /* Keep back button vertically aligned. */\n margin-bottom: var(--space-xsmall);\n}\n\n.PageHeader-title {\n font-size: var(--text-title-size-medium);\n font-weight: var(--base-text-weight-normal);\n flex: 1 1 auto;\n}\n\n.PageHeader-title--large {\n font-size: var(--text-title-size-large);\n}\n\n/* One-liner of supporting text */\n.PageHeader-description {\n font-size: var(--text-body-size-medium);\n color: var(--fgColor-muted);\n flex: 1 100%;\n}\n\n.PageHeader-actions {\n justify-content: flex-end;\n display: flex;\n align-items: center;\n}\n\n.PageHeader-breadcrumbs {\n display: block;\n width: 100%;\n}\n\n.PageHeader-leadingAction {\n margin-top: 2px; /* to center align with label */\n margin-right: var(--base-size-4);\n}\n\n.PageHeader-parentLink {\n flex: 1 1 auto;\n}\n\n.PageHeader-tabNav {\n margin-top: var(--stack-gap-normal);\n margin-bottom: 0;\n}\n"]}
@@ -27,4 +27,5 @@
27
27
  </div>
28
28
 
29
29
  <%= description %>
30
+ <%= tab_nav %>
30
31
  <% end %>
@@ -8,6 +8,11 @@
8
8
  flex-flow: column;
9
9
  }
10
10
 
11
+ .PageHeader--noBorder {
12
+ border-bottom: none;
13
+ padding-bottom: 0;
14
+ }
15
+
11
16
  .PageHeader-contextBar {
12
17
  display: flex;
13
18
  flex-flow: row;
@@ -60,3 +65,8 @@
60
65
  .PageHeader-parentLink {
61
66
  flex: 1 1 auto;
62
67
  }
68
+
69
+ .PageHeader-tabNav {
70
+ margin-top: var(--stack-gap-normal);
71
+ margin-bottom: 0;
72
+ }
@@ -205,6 +205,19 @@ module Primer
205
205
  end
206
206
  }
207
207
 
208
+ # Optional tabs nav at the bottom of the page header
209
+ #
210
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
211
+ renders_one :tab_nav, lambda { |**system_arguments, &block|
212
+ @system_arguments[:classes] = class_names(@system_arguments[:classes], "PageHeader--noBorder")
213
+
214
+ system_arguments = deny_tag_argument(**system_arguments)
215
+ system_arguments[:tag] = :div
216
+ system_arguments[:classes] = class_names(system_arguments[:classes], "PageHeader-tabNav")
217
+
218
+ Primer::Alpha::TabNav.new(**system_arguments, &block)
219
+ }
220
+
208
221
  # @param mobile_menu_label [String] The tooltip label of the mobile menu
209
222
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
210
223
  def initialize(mobile_menu_label: I18n.t("label_more"), **system_arguments)
@@ -12,7 +12,6 @@
12
12
  @import "./alpha/button_marketing.pcss";
13
13
  @import "./alpha/toggle_switch.pcss";
14
14
  @import "./alpha/underline_nav.pcss";
15
- @import "./alpha/underline_panels.pcss";
16
15
  @import "./alpha/segmented_control.pcss";
17
16
  @import "./alpha/menu.pcss";
18
17
 
@@ -5,7 +5,7 @@ module Primer
5
5
  module ViewComponents
6
6
  module VERSION
7
7
  MAJOR = 0
8
- MINOR = 30
8
+ MINOR = 31
9
9
  PATCH = 0
10
10
 
11
11
  STRING = [MAJOR, MINOR, PATCH].join(".")
@@ -14,4 +14,11 @@
14
14
  <% end %>
15
15
  <% end %>
16
16
  <% end %>
17
+ <% if with_tab_nav %>
18
+ <% header.with_tab_nav(label: "label") do |nav|%>
19
+ <% nav.with_tab(selected: true, href: "#") { "Tab 1" } %>
20
+ <% nav.with_tab(href: "#") { "Tab 2" } %>
21
+ <% nav.with_tab(href: "#") { "Tab 3" } %>
22
+ <% end %>
23
+ <% end %>
17
24
  <% end %>
@@ -23,12 +23,14 @@ module Primer
23
23
  # @param description [String] text
24
24
  # @param with_leading_action [Symbol] octicon
25
25
  # @param with_actions [Boolean]
26
+ # @param with_tab_nav [Boolean]
26
27
  def playground(
27
28
  variant: :medium,
28
29
  title: "Hello",
29
30
  description: "Last updated 5 minutes ago by XYZ.",
30
31
  with_leading_action: :"none",
31
- with_actions: true
32
+ with_actions: true,
33
+ with_tab_nav: false
32
34
  )
33
35
  breadcrumb_items = [{ href: "/foo", text: "Foo" }, { href: "/bar", text: "Bar" }, "Baz"]
34
36
 
@@ -37,7 +39,8 @@ module Primer
37
39
  description: description,
38
40
  with_leading_action: with_leading_action,
39
41
  with_actions: with_actions,
40
- breadcrumb_items: breadcrumb_items })
42
+ breadcrumb_items: breadcrumb_items,
43
+ with_tab_nav: with_tab_nav})
41
44
  end
42
45
 
43
46
  # @label Large title
@@ -167,6 +170,23 @@ module Primer
167
170
  header.with_breadcrumbs(breadcrumb_items, selected_item_font_weight: :normal)
168
171
  end
169
172
  end
173
+
174
+ # @label With tab nav
175
+ #
176
+ def tab_nav
177
+ render(Primer::OpenProject::PageHeader.new) do |header|
178
+ header.with_title { "Hello" }
179
+ header.with_breadcrumbs([{ href: "/foo", text: "Foo" }, { href: "/bar", text: "Bar" }, "Baz"])
180
+ header.with_description { "Last updated 5 minutes ago by XYZ." }
181
+ header.with_tab_nav(label: "label") do |nav|
182
+ Array.new(3) do |i|
183
+ nav.with_tab(selected: i.zero? , href: "#") do |tab|
184
+ tab.with_text { "Tab #{i + 1}" }
185
+ end
186
+ end
187
+ end
188
+ end
189
+ end
170
190
  end
171
191
  end
172
192
  end
@@ -2462,6 +2462,18 @@
2462
2462
  "default": "N/A",
2463
2463
  "description": "One of `:left` or `:right`. - Defaults to left"
2464
2464
  },
2465
+ {
2466
+ "name": "body_arguments",
2467
+ "type": "Hash",
2468
+ "default": "`{}`",
2469
+ "description": "[System arguments](/system-arguments) for the body wrapper."
2470
+ },
2471
+ {
2472
+ "name": "wrapper_arguments",
2473
+ "type": "Hash",
2474
+ "default": "`{}`",
2475
+ "description": "[System arguments](/system-arguments) for the `TabContainer` wrapper."
2476
+ },
2465
2477
  {
2466
2478
  "name": "system_arguments",
2467
2479
  "type": "Hash",
data/static/classes.json CHANGED
@@ -429,6 +429,9 @@
429
429
  "PageHeader": [
430
430
  "Primer::OpenProject::PageHeader"
431
431
  ],
432
+ "PageHeader--noBorder": [
433
+ "Primer::OpenProject::PageHeader"
434
+ ],
432
435
  "PageHeader-actions": [
433
436
  "Primer::OpenProject::PageHeader"
434
437
  ],
@@ -447,6 +450,9 @@
447
450
  "PageHeader-parentLink": [
448
451
  "Primer::OpenProject::PageHeader"
449
452
  ],
453
+ "PageHeader-tabNav": [
454
+ "Primer::OpenProject::PageHeader"
455
+ ],
450
456
  "PageHeader-title": [
451
457
  "Primer::OpenProject::PageHeader"
452
458
  ],
@@ -2284,7 +2284,7 @@
2284
2284
  {
2285
2285
  "fully_qualified_name": "Primer::Alpha::Banner",
2286
2286
  "description": "Use `Banner` to highlight important information.",
2287
- "accessibility_docs": "Given that Banner is made visually prominent to sighted users through the use of icons and color, consider providing a heading and designating the Banner as a region landmark to improve navigability and discoverability of the Banner of assistive technology users. At this time, the PVC Banner does not render a heading nor render as a region landmark by default. This may be introduced in the future [as a breaking API change](https://github.com/primer/view_components/issues/2619). For now, consider providing an appropriate heading inside of the Banner and rendering the Banner as a `<section>` tag with `aria-labelledby=\"switch-this-with-banner-heading-id\"` to implicitly designate the Banner as a region landmark.\n\nA Banner can be used in one of two ways – to highlight information on a page, or to communicate an urgent message/feedback for a user action. For the latter scenario, it may be necessary to use a live region or focus management technique to ensure that the Banner is discoverable and accessible for all users. Otherwise, the Banner can easily be missed, including by those using magnification software or screen reader users who may not realize that a Banner has appeared. The appropriate technique to use is highly context-dependent. Visit the [Banner's Accessibility section](https://primer.style/components/banner#accessibility) or defer to the accessibility team to determine if your scenario requires either techniques.\n\n### Announcing a Banner\n When a Banner is used to communicate non-critical feedback, or is used in critical scenarios where moving focus is considered too disruptive, use a live region announcement to announce the content of the Banner to screen reader users.\n\n Live regions can be finicky and don't work well when injected dynamically. Setting a live region attribute on the Banner itself is discouraged as it will not announce as expected for most screen readers.\n\n To ensure a Banner is announced reliably, make sure that there's a live region container that is already on the page. When the Banner is shown, populate the live region container with the content of the Banner. This can be done in one of two ways. The first is to rely on a global live region container that is guaranteed to be on the page. When the Banner appears, populate this global live region container with the Banner content. The second technique is to hide or show the Banner within a live region wrapper that is guaranteed to always be on the page.\n\n For more information about either technique, visit [Staff only: Challenges with live regions](https://github.com/github/accessibility/blob/main/docs/coaching-recommendations/toast-flash-banner/accessible-banner-prototype.md#challenges-with-dynamically-inserted-live-region). This guidance is subject to change.\n\n### Focusing a Banner\n Focusing a Banner when it appears helps to maximize discoverability of the message, especially in critical scenarios.\n\n To properly focus a banner, add a `tabindex=\"-1\"` to the Banner container, and focus that container (one way is using the [`focus()` API](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus)).\n\n For more information about the focus management technique, visit the [Staff only: Accessible Banner Prototype docs](https://github.com/github/accessibility/blob/main/docs/coaching-recommendations/toast-flash-banner/accessible-banner-prototype.md#consideration). This guidance is subject to change.",
2287
+ "accessibility_docs": "### Improve discoverability with a heading and landmark\nBanners are made visually prominent with icons and colors to immediately draw attention.\n\nTo ensure the Banner is also easily discoverable for assistive technology users, consider:\n1. Providing a heading inside of the Banner that describes the purpose of the Banner.\n2. Designating the Banner as a `region` landmark. This can be achieved by rendering the Banner as a `section` with an `aria-labelledby` pointing to the heading.\n\n### Communicating feedback\nWhen a Banner is used to communicate feedback, a live region or focus management technique should be in place to ensure that assistive technology users are aware of the feedback, especially when the Banner is shown client-side. Visit the [Banner's Accessibility section](https://primer.style/components/banner#accessibility), or defer to the accessibility team.\n\n#### Approach 1: Announcing a Banner\nA live region announcement can be used to communicate non-critical feedback, such as a success message.\n\nTo successfully trigger a live region announcement for a Banner that is un-`hidden` or dynamically injected onto the page, **do not** set the live region attribute/role on the Banner itself. Instead, it's important to rely on a live region that is already guaranteed to be on the page. Learn more about specific techniques at: [Staff only: Challenges with live regions](https://github.com/github/accessibility/blob/main/docs/coaching-recommendations/toast-flash-banner/accessible-banner-prototype.md#challenges-with-dynamically-inserted-live-region).\n\n#### Approach 2: Focusing a Banner\nFocusing the Banner can be appropriate for critical feedback scenarios, such as a [form validation error summary](https://primer.style/ui-patterns/forms/overview#interactive-summary-of-errors) where the Banner contains actions to help unblock the user.\n\nTo properly focus a Banner, add a `tabindex=\"-1\"` place focus with JavaScript (using the [`focus()` API](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus)).",
2288
2288
  "is_form_component": false,
2289
2289
  "is_published": true,
2290
2290
  "requires_js": true,
@@ -7628,6 +7628,18 @@
7628
7628
  "default": "N/A",
7629
7629
  "description": "One of `:left` or `:right`. - Defaults to left"
7630
7630
  },
7631
+ {
7632
+ "name": "body_arguments",
7633
+ "type": "Hash",
7634
+ "default": "`{}`",
7635
+ "description": "{{link_to_system_arguments_docs}} for the body wrapper."
7636
+ },
7637
+ {
7638
+ "name": "wrapper_arguments",
7639
+ "type": "Hash",
7640
+ "default": "`{}`",
7641
+ "description": "{{link_to_system_arguments_docs}} for the `TabContainer` wrapper."
7642
+ },
7631
7643
  {
7632
7644
  "name": "system_arguments",
7633
7645
  "type": "Hash",
@@ -16680,6 +16692,18 @@
16680
16692
  "description": "{{link_to_system_arguments_docs}}"
16681
16693
  }
16682
16694
  ]
16695
+ },
16696
+ {
16697
+ "name": "tab_nav",
16698
+ "description": "Optional tabs nav at the bottom of the page header",
16699
+ "parameters": [
16700
+ {
16701
+ "name": "system_arguments",
16702
+ "type": "Hash",
16703
+ "default": "N/A",
16704
+ "description": "{{link_to_system_arguments_docs}}"
16705
+ }
16706
+ ]
16683
16707
  }
16684
16708
  ],
16685
16709
  "methods": [
@@ -16828,6 +16852,19 @@
16828
16852
  "color-contrast"
16829
16853
  ]
16830
16854
  }
16855
+ },
16856
+ {
16857
+ "preview_path": "primer/open_project/page_header/tab_nav",
16858
+ "name": "tab_nav",
16859
+ "snapshot": "false",
16860
+ "skip_rules": {
16861
+ "wont_fix": [
16862
+ "region"
16863
+ ],
16864
+ "will_fix": [
16865
+ "color-contrast"
16866
+ ]
16867
+ }
16831
16868
  }
16832
16869
  ],
16833
16870
  "subcomponents": [
data/static/previews.json CHANGED
@@ -5390,6 +5390,19 @@
5390
5390
  "color-contrast"
5391
5391
  ]
5392
5392
  }
5393
+ },
5394
+ {
5395
+ "preview_path": "primer/open_project/page_header/tab_nav",
5396
+ "name": "tab_nav",
5397
+ "snapshot": "false",
5398
+ "skip_rules": {
5399
+ "wont_fix": [
5400
+ "region"
5401
+ ],
5402
+ "will_fix": [
5403
+ "color-contrast"
5404
+ ]
5405
+ }
5393
5406
  }
5394
5407
  ]
5395
5408
  },