primer_view_components 0.0.123 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +36 -0
- data/app/assets/javascripts/primer_view_components.js +1 -1
- data/app/assets/javascripts/primer_view_components.js.map +1 -1
- data/app/assets/styles/primer_view_components.css +2 -2
- data/app/assets/styles/primer_view_components.css.map +1 -1
- data/app/components/primer/alpha/action_list/divider.rb +2 -2
- data/app/components/primer/alpha/action_list/heading.html.erb +1 -1
- data/app/components/primer/alpha/action_list/heading.rb +10 -4
- data/app/components/primer/alpha/action_list/item.rb +7 -3
- data/app/components/primer/alpha/action_list.css.json +41 -0
- data/app/components/primer/alpha/action_list.html.erb +6 -8
- data/app/components/primer/alpha/action_list.rb +5 -10
- data/app/components/primer/alpha/auto_complete.css.json +11 -0
- data/app/components/primer/alpha/banner.css.json +14 -0
- data/app/components/primer/alpha/button_marketing.css.json +10 -0
- data/app/components/primer/alpha/dialog.css.json +63 -0
- data/app/components/primer/alpha/dropdown.css.json +21 -0
- data/app/components/primer/alpha/layout.css.json +27 -0
- data/app/components/primer/alpha/menu.css.json +11 -0
- data/app/components/primer/alpha/nav_list/{section.rb → group.rb} +9 -9
- data/app/components/primer/alpha/nav_list/item.html.erb +1 -1
- data/app/components/primer/alpha/nav_list/item.rb +18 -2
- data/app/components/primer/alpha/nav_list.d.ts +1 -0
- data/app/components/primer/alpha/nav_list.html.erb +8 -8
- data/app/components/primer/alpha/nav_list.js +24 -0
- data/app/components/primer/alpha/nav_list.rb +28 -32
- data/app/components/primer/alpha/nav_list.ts +27 -0
- data/app/components/primer/alpha/navigation/tab.rb +168 -0
- data/app/components/primer/alpha/overlay/body.rb +26 -0
- data/app/components/primer/alpha/overlay/footer.rb +41 -0
- data/app/components/primer/alpha/overlay/header.html.erb +15 -0
- data/app/components/primer/alpha/overlay/header.rb +47 -0
- data/app/components/primer/alpha/overlay.css +1 -0
- data/app/components/primer/alpha/overlay.css.json +11 -0
- data/app/components/primer/alpha/overlay.css.map +1 -0
- data/app/components/primer/alpha/overlay.html.erb +11 -0
- data/app/components/primer/alpha/overlay.pcss +14 -0
- data/app/components/primer/alpha/overlay.rb +207 -0
- data/app/components/primer/alpha/segmented_control.css.json +15 -0
- data/app/components/primer/alpha/tab_nav.css.json +10 -0
- data/app/components/primer/alpha/tab_nav.rb +10 -3
- data/app/components/primer/alpha/tab_panels.rb +2 -2
- data/app/components/primer/alpha/text_field.css.json +38 -0
- data/app/components/primer/alpha/toggle_switch.css.json +16 -0
- data/app/components/primer/alpha/underline_nav.css +1 -1
- data/app/components/primer/alpha/underline_nav.css.json +13 -0
- data/app/components/primer/alpha/underline_nav.css.map +1 -1
- data/app/components/primer/alpha/underline_nav.pcss +1 -0
- data/app/components/primer/alpha/underline_nav.rb +2 -2
- data/app/components/primer/alpha/underline_panels.rb +2 -2
- data/app/components/primer/anchored_position.d.ts +27 -0
- data/app/components/primer/anchored_position.js +149 -0
- data/app/components/primer/anchored_position.ts +167 -0
- data/app/components/primer/beta/avatar.css.json +14 -0
- data/app/components/primer/beta/avatar_stack.css.json +9 -0
- data/app/components/primer/beta/blankslate.css.json +12 -0
- data/app/components/primer/beta/border_box.css.json +32 -0
- data/app/components/primer/beta/breadcrumbs.css.json +4 -0
- data/app/components/primer/beta/button.css.json +22 -0
- data/app/components/primer/beta/button.html.erb +1 -1
- data/app/components/primer/beta/button.rb +2 -1
- data/app/components/primer/beta/counter.css.json +6 -0
- data/app/components/primer/beta/flash.css.json +15 -0
- data/app/components/primer/beta/flash.html.erb +1 -2
- data/app/components/primer/beta/label.css.json +20 -0
- data/app/components/primer/beta/link.css.json +8 -0
- data/app/components/primer/beta/popover.css.json +18 -0
- data/app/components/primer/beta/progress_bar.css.json +6 -0
- data/app/components/primer/beta/state.css.json +10 -0
- data/app/components/primer/beta/subhead.css.json +8 -0
- data/app/components/primer/beta/timeline_item.css.json +9 -0
- data/app/components/primer/beta/truncate.css.json +6 -0
- data/app/components/primer/component.rb +34 -0
- data/app/components/primer/navigation/tab_component.rb +3 -157
- data/app/components/primer/primer.d.ts +2 -0
- data/app/components/primer/primer.js +2 -0
- data/app/components/primer/primer.pcss +3 -0
- data/app/components/primer/primer.ts +2 -0
- data/app/components/primer/truncate.css.json +7 -0
- data/app/lib/primer/css/layout.css.json +263 -0
- data/app/lib/primer/css/utilities.css.json +1636 -0
- data/lib/primer/deprecations.yml +4 -0
- data/lib/primer/view_components/linters/base_linter.rb +1 -1
- data/lib/primer/view_components/linters/disallow_component_css_counter.rb +30 -0
- data/lib/primer/view_components/version.rb +2 -2
- data/lib/primer/yard/component_manifest.rb +3 -1
- data/lib/tasks/docs.rake +1 -1
- data/previews/primer/alpha/action_list_preview.rb +6 -14
- data/previews/primer/alpha/nav_list_preview/trailing_action.html.erb +19 -0
- data/previews/primer/alpha/nav_list_preview.rb +19 -30
- data/previews/primer/alpha/overlay_preview/middle_of_page.html.erb +17 -0
- data/previews/primer/alpha/overlay_preview.rb +112 -0
- data/previews/primer/alpha/tab_nav_preview/with_extra.html.erb +8 -0
- data/previews/primer/alpha/tab_nav_preview.rb +5 -0
- data/previews/primer/alpha/tab_panels_preview/with_extra.html.erb +17 -0
- data/previews/primer/alpha/tab_panels_preview.rb +5 -0
- data/static/arguments.json +167 -7
- data/static/audited_at.json +6 -1
- data/static/classes.json +311 -0
- data/static/constants.json +122 -8
- data/static/previews.json +31 -0
- data/static/statuses.json +7 -2
- metadata +25 -6
- data/app/components/primer/alpha/nav_list/section.html.erb +0 -3
- data/previews/primer/alpha/action_list_preview/heading.html.erb +0 -4
- /data/app/components/primer/{navigation/tab_component.html.erb → alpha/navigation/tab.html.erb} +0 -0
@@ -3,13 +3,13 @@
|
|
3
3
|
module Primer
|
4
4
|
module Alpha
|
5
5
|
# `NavList` provides a simple way to render side navigation, i.e. navigation
|
6
|
-
# that appears to the left or right side of some main content. Each
|
6
|
+
# that appears to the left or right side of some main content. Each group in a
|
7
7
|
# nav list is a list of links.
|
8
8
|
#
|
9
|
-
# Nav list
|
9
|
+
# Nav list groups can contain sub items. Rather than navigating to a URL, groups
|
10
10
|
# with sub items expand and collapse on click. To indicate this functionality, the
|
11
|
-
#
|
12
|
-
# when the
|
11
|
+
# group will automatically render with a trailing chevron icon that changes direction
|
12
|
+
# when the group expands and collapses.
|
13
13
|
#
|
14
14
|
# Nav list items appear visually active when selected. Each nav item must have one
|
15
15
|
# or more ID values that determine which item will appear selected. Use the
|
@@ -22,40 +22,40 @@ module Primer
|
|
22
22
|
"nav-list"
|
23
23
|
end
|
24
24
|
|
25
|
-
#
|
25
|
+
# Groups. Each group is a list of links and an optional heading.
|
26
26
|
#
|
27
|
-
# @param system_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Alpha::NavList::
|
28
|
-
renders_many :
|
29
|
-
Primer::Alpha::NavList::
|
27
|
+
# @param system_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Alpha::NavList::Group) %>.
|
28
|
+
renders_many :groups, lambda { |**system_arguments|
|
29
|
+
Primer::Alpha::NavList::Group.new(selected_item_id: @selected_item_id, **system_arguments)
|
30
30
|
}
|
31
31
|
|
32
32
|
# @example Items and headings
|
33
33
|
#
|
34
34
|
# <%= render(Primer::Alpha::NavList.new(selected_item_id: :personal_info)) do |component| %>
|
35
|
-
# <% component.
|
36
|
-
# <%
|
35
|
+
# <% component.with_group(aria: { label: "Settings" }) do |group| %>
|
36
|
+
# <% group.with_item(label: "General", selected_by_ids: :general, href: "/settings/general") %>
|
37
37
|
# <% end %>
|
38
|
-
# <% component.
|
39
|
-
# <%
|
40
|
-
# <%
|
41
|
-
# <%
|
42
|
-
# <%
|
38
|
+
# <% component.with_group do |group| %>
|
39
|
+
# <% group.with_heading(title: "Account Settings") %>
|
40
|
+
# <% group.with_item(label: "Personal Information", selected_by_ids: :personal_info, href: "/account/info") %>
|
41
|
+
# <% group.with_item(label: "Password", selected_by_ids: :password, href: "/account/password") %>
|
42
|
+
# <% group.with_item(label: "Billing info", selected_by_ids: :billing, href: "/account/billing") %>
|
43
43
|
# <% end %>
|
44
44
|
# <% end %>
|
45
45
|
#
|
46
46
|
# @example Leading and trailing visuals
|
47
47
|
#
|
48
48
|
# <%= render(Primer::Alpha::NavList.new(selected_item_id: :personal_info)) do |component| %>
|
49
|
-
# <% component.
|
50
|
-
# <%
|
51
|
-
# <%
|
49
|
+
# <% component.with_group do |group| %>
|
50
|
+
# <% group.with_heading(title: "Account Settings") %>
|
51
|
+
# <% group.with_item(label: "Personal Information", selected_by_ids: :personal_info, href: "/account/info") do |item| %>
|
52
52
|
# <% item.with_leading_visual_avatar(src: "https://github.com/github.png", alt: "GitHub") %>
|
53
53
|
# <% end %>
|
54
|
-
# <%
|
54
|
+
# <% group.with_item(label: "Notifications", selected_by_ids: :notifications, href: "/account/notifications") do |item| %>
|
55
55
|
# <% item.with_leading_visual_icon(icon: :bell) %>
|
56
56
|
# <% item.with_trailing_visual_counter(count: 15) %>
|
57
57
|
# <% end %>
|
58
|
-
# <%
|
58
|
+
# <% group.with_item(label: "Billing info", selected_by_ids: :billing, href: "/account/billing") do |item| %>
|
59
59
|
# <% item.with_leading_visual_icon(icon: :package) %>
|
60
60
|
# <% item.with_trailing_visual_icon(icon: :"dot-fill", color: :attention) %>
|
61
61
|
# <% end %>
|
@@ -65,9 +65,9 @@ module Primer
|
|
65
65
|
# @example Expandable sub items
|
66
66
|
#
|
67
67
|
# <%= render(Primer::Alpha::NavList.new(selected_item_id: :email_notifications)) do |component| %>
|
68
|
-
# <% component.
|
69
|
-
# <%
|
70
|
-
# <%
|
68
|
+
# <% component.with_group do |group| %>
|
69
|
+
# <% group.with_heading(title: "Account Settings") %>
|
70
|
+
# <% group.with_item(label: "Notification settings") do |item| %>
|
71
71
|
# <% item.with_leading_visual_icon(icon: :bell) %>
|
72
72
|
# <% item.with_item(label: "Email", selected_by_ids: :email_notifications, href: "/account/notifications/email") do |subitem| %>
|
73
73
|
# <% subitem.with_trailing_visual_icon(icon: :mail) %>
|
@@ -76,7 +76,7 @@ module Primer
|
|
76
76
|
# <% subitem.with_trailing_visual_icon(icon: :"device-mobile") %>
|
77
77
|
# <% end %>
|
78
78
|
# <% end %>
|
79
|
-
# <%
|
79
|
+
# <% group.with_item(label: "Messages") do |item| %>
|
80
80
|
# <% item.with_leading_visual_icon(icon: :bookmark) %>
|
81
81
|
# <% item.with_item(label: "Inbox", href: "/account/messages/inbox") do |subitem| %>
|
82
82
|
# <% subitem.with_trailing_visual_counter(count: 10) %>
|
@@ -91,12 +91,12 @@ module Primer
|
|
91
91
|
# @example Trailing action
|
92
92
|
#
|
93
93
|
# <%= render(Primer::Alpha::NavList.new) do |component| %>
|
94
|
-
# <% component.
|
95
|
-
# <%
|
96
|
-
# <%
|
94
|
+
# <% component.with_group do |group| %>
|
95
|
+
# <% group.with_heading(title: "My Favorite Foods") %>
|
96
|
+
# <% group.with_item(label: "Popplers", selected_by_ids: :popplers, href: "/foods/popplers") do |item| %>
|
97
97
|
# <% item.with_trailing_action(show_on_hover: false, icon: "plus", "aria-label": "Add new food", size: :medium) %>
|
98
98
|
# <% end %>
|
99
|
-
# <%
|
99
|
+
# <% group.with_item(label: "Slurm", selected_by_ids: :slurm, href: "/foods/slurm") do |item| %>
|
100
100
|
# <% item.with_trailing_action(show_on_hover: true, icon: "plus", "aria-label": "Add new food", size: :medium) %>
|
101
101
|
# <% end %>
|
102
102
|
# <% end %>
|
@@ -106,10 +106,6 @@ module Primer
|
|
106
106
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
107
107
|
def initialize(selected_item_id: nil, **system_arguments)
|
108
108
|
@system_arguments = system_arguments
|
109
|
-
@system_arguments[:classes] = class_names(
|
110
|
-
@system_arguments[:classes],
|
111
|
-
"ActionListWrap"
|
112
|
-
)
|
113
109
|
@selected_item_id = selected_item_id
|
114
110
|
end
|
115
111
|
end
|
@@ -87,6 +87,7 @@ export class NavListElement extends HTMLElement {
|
|
87
87
|
collapseItem(item: HTMLElement) {
|
88
88
|
item.nextElementSibling?.setAttribute('data-hidden', '')
|
89
89
|
item.setAttribute('aria-expanded', 'false')
|
90
|
+
item.focus()
|
90
91
|
}
|
91
92
|
|
92
93
|
itemIsExpanded(item: HTMLElement | null) {
|
@@ -112,6 +113,28 @@ export class NavListElement extends HTMLElement {
|
|
112
113
|
e.stopPropagation()
|
113
114
|
}
|
114
115
|
|
116
|
+
// collapse item
|
117
|
+
handleItemWithSubItemKeydown(e: KeyboardEvent) {
|
118
|
+
const el = e.currentTarget
|
119
|
+
if (!(el instanceof HTMLElement)) return
|
120
|
+
|
121
|
+
let button = el.closest<HTMLButtonElement>('button')
|
122
|
+
if (!button) {
|
123
|
+
const button_id = el.getAttribute('aria-labelledby')
|
124
|
+
if (button_id) {
|
125
|
+
button = document.getElementById(button_id) as HTMLButtonElement
|
126
|
+
} else {
|
127
|
+
return
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
if (this.itemIsExpanded(button) && e.key === 'Escape') {
|
132
|
+
this.collapseItem(button)
|
133
|
+
}
|
134
|
+
|
135
|
+
e.stopPropagation()
|
136
|
+
}
|
137
|
+
|
115
138
|
private async showMore(e: Event) {
|
116
139
|
e.preventDefault()
|
117
140
|
if (this.showMoreDisabled) return
|
@@ -162,6 +185,10 @@ export class NavListElement extends HTMLElement {
|
|
162
185
|
#findSelectedNavItemById(itemId: string): HTMLElement | null {
|
163
186
|
// First we compare the selected link to data-item-id for each nav item
|
164
187
|
for (const navItem of this.items) {
|
188
|
+
if (navItem.classList.contains('ActionListItem--hasSubItem')) {
|
189
|
+
continue
|
190
|
+
}
|
191
|
+
|
165
192
|
const keys = navItem.getAttribute('data-item-id')?.split(' ') || []
|
166
193
|
|
167
194
|
if (keys.includes(itemId)) {
|
@@ -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
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Primer
|
4
|
+
module Alpha
|
5
|
+
class Overlay
|
6
|
+
# A `Overlay::Body` is a compositional component, used to render the
|
7
|
+
# Body of an overlay. See <%= link_to_component(Primer::Alpha::Overlay) %>.
|
8
|
+
class Body < Primer::Component
|
9
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
10
|
+
def initialize(padding: DEFAULT_PADDING, **system_arguments)
|
11
|
+
@system_arguments = deny_tag_argument(**system_arguments)
|
12
|
+
@system_arguments[:tag] = :div
|
13
|
+
@system_arguments[:classes] = class_names(
|
14
|
+
"Overlay-body",
|
15
|
+
PADDING_MAPPINGS[fetch_or_fallback(PADDING_OPTIONS, padding, DEFAULT_PADDING)],
|
16
|
+
system_arguments[:classes]
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
def call
|
21
|
+
render(Primer::BaseComponent.new(**@system_arguments)) { content }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Primer
|
4
|
+
module Alpha
|
5
|
+
class Overlay
|
6
|
+
DEFAULT_ALIGN_CONTENT = :end
|
7
|
+
ALIGN_CONTENT_MAPPINGS = {
|
8
|
+
:start => "Overlay-footer--alignStart",
|
9
|
+
:center => "Overlay-footer--alignCenter",
|
10
|
+
DEFAULT_ALIGN_CONTENT => "Overlay-footer--alignEnd"
|
11
|
+
}.freeze
|
12
|
+
ALIGN_CONTENT_OPTIONS = ALIGN_CONTENT_MAPPINGS.keys
|
13
|
+
|
14
|
+
# A `Overlay::Footer` is a compositional component, used to render the
|
15
|
+
# Footer of an overlay. See <%= link_to_component(Primer::Alpha::Overlay) %>.
|
16
|
+
class Footer < Primer::Component
|
17
|
+
# @param show_divider [Boolean] Show a divider between the footer and body.
|
18
|
+
# @param align_content [Symbol] The alginment of contents. <%= one_of(Primer::Alpha::Overlay::ALIGN_CONTENT_OPTIONS) %>
|
19
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
20
|
+
def initialize(
|
21
|
+
show_divider: false,
|
22
|
+
align_content: DEFAULT_ALIGN_CONTENT,
|
23
|
+
**system_arguments
|
24
|
+
)
|
25
|
+
@system_arguments = deny_tag_argument(**system_arguments)
|
26
|
+
@system_arguments[:tag] = :div
|
27
|
+
@system_arguments[:classes] = class_names(
|
28
|
+
"Overlay-footer",
|
29
|
+
ALIGN_CONTENT_MAPPINGS[fetch_or_fallback(ALIGN_CONTENT_OPTIONS, align_content, DEFAULT_ALIGN_CONTENT)],
|
30
|
+
{ "Overlay-footer--divided": show_divider },
|
31
|
+
system_arguments[:classes]
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
def call
|
36
|
+
render(Primer::BaseComponent.new(**@system_arguments)) { content }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<%= render Primer::BaseComponent.new(**@system_arguments) do %>
|
2
|
+
<div class="Overlay-headerContentWrap">
|
3
|
+
<div class="Overlay-titleWrap">
|
4
|
+
<h1 class="Overlay-title <% if @visually_hide_title || content.present? %>sr-only<% end %>"><%= @title %></h1>
|
5
|
+
<% if content.present? %>
|
6
|
+
<%= content %>
|
7
|
+
<% elsif @subtitle.present? %>
|
8
|
+
<h2 id="<%= @id %>-description" class="Overlay-description"><%= @subtitle %></h2>
|
9
|
+
<% end %>
|
10
|
+
</div>
|
11
|
+
<div class="Overlay-actionWrap">
|
12
|
+
<%= render Primer::Beta::CloseButton.new(classes: "Overlay-closeButton", "popoverhidetarget": @id) %>
|
13
|
+
</div>
|
14
|
+
</div>
|
15
|
+
<% end %>
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Primer
|
4
|
+
module Alpha
|
5
|
+
class Overlay
|
6
|
+
# A `Overlay::Header` is a compositional component, used to render the
|
7
|
+
# Header of an overlay. See <%= link_to_component(Primer::Alpha::Overlay) %>.
|
8
|
+
class Header < Primer::Component
|
9
|
+
DEFAULT_SIZE = :medium
|
10
|
+
SIZE_MAPPINGS = {
|
11
|
+
DEFAULT_SIZE => nil,
|
12
|
+
:large => "Overlay-header--large"
|
13
|
+
}.freeze
|
14
|
+
SIZE_OPTIONS = SIZE_MAPPINGS.keys
|
15
|
+
|
16
|
+
# @param title [String] Describes the content of the Overlay.
|
17
|
+
# @param subtitle [String] Provides dditional context for the Overlay, also setting the `aria-describedby` attribute.
|
18
|
+
# @param size [Symbol] The size of the Header. <%= one_of(Primer::Alpha::Overlay::Header::SIZE_OPTIONS) %>
|
19
|
+
# @param divider [Boolean] Show a divider between the header and body.
|
20
|
+
# @param visually_hide_title [Boolean] Visually hide the `title` while maintaining a label for assistive technologies.
|
21
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
22
|
+
def initialize(
|
23
|
+
id:,
|
24
|
+
title:,
|
25
|
+
subtitle: nil,
|
26
|
+
size: DEFAULT_SIZE,
|
27
|
+
divider: false,
|
28
|
+
visually_hide_title: false,
|
29
|
+
**system_arguments
|
30
|
+
)
|
31
|
+
@id = id
|
32
|
+
@title = title
|
33
|
+
@subtitle = subtitle
|
34
|
+
@visually_hide_title = visually_hide_title
|
35
|
+
@system_arguments = deny_tag_argument(**system_arguments)
|
36
|
+
@system_arguments[:tag] = :header
|
37
|
+
@system_arguments[:classes] = class_names(
|
38
|
+
"Overlay-header",
|
39
|
+
{ "Overlay-header--divided": divider },
|
40
|
+
SIZE_MAPPINGS[fetch_or_fallback(SIZE_OPTIONS, size, DEFAULT_SIZE)],
|
41
|
+
system_arguments[:classes]
|
42
|
+
)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
.Overlay[popover]{border-width:0;padding:0;position:absolute}.Overlay[popover]:not(:open){display:none}anchored-position{display:block}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["overlay.pcss"],"names":[],"mappings":"AAAA,kBACE,cAAe,CACf,SAAU,CACV,iBACF,CAGA,6BACE,YACF,CAEA,kBACE,aACF","file":"overlay.css","sourcesContent":[".Overlay[popover] {\n border-width: 0;\n padding: 0;\n position: absolute;\n}\n\n/* stylelint-disable-next-line selector-pseudo-class-no-unknown */\n.Overlay[popover]:not(:open) {\n display: none;\n}\n\nanchored-position {\n display: block;\n}\n"]}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
.Overlay[popover] {
|
2
|
+
border-width: 0;
|
3
|
+
padding: 0;
|
4
|
+
position: absolute;
|
5
|
+
}
|
6
|
+
|
7
|
+
/* stylelint-disable-next-line selector-pseudo-class-no-unknown */
|
8
|
+
.Overlay[popover]:not(:open) {
|
9
|
+
display: none;
|
10
|
+
}
|
11
|
+
|
12
|
+
anchored-position {
|
13
|
+
display: block;
|
14
|
+
}
|