primer_view_components 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +40 -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 +1 -1
- 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 +11 -5
- data/app/components/primer/alpha/action_list/item.rb +19 -15
- data/app/components/primer/alpha/action_list.html.erb +7 -8
- data/app/components/primer/alpha/action_list.rb +16 -11
- data/app/components/primer/alpha/nav_list/{section.rb → group.rb} +5 -5
- data/app/components/primer/alpha/nav_list/item.html.erb +1 -1
- data/app/components/primer/alpha/nav_list/item.rb +15 -1
- 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 +21 -0
- data/app/components/primer/alpha/nav_list.rb +30 -34
- data/app/components/primer/alpha/nav_list.ts +23 -0
- data/app/components/primer/alpha/navigation/tab.rb +168 -0
- data/app/components/primer/alpha/overlay/header.html.erb +2 -2
- data/app/components/primer/alpha/overlay.rb +29 -9
- 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/underline_nav.css +1 -1
- 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/beta/button.html.erb +1 -1
- data/app/components/primer/beta/button.rb +2 -1
- data/app/components/primer/component.rb +34 -0
- data/app/components/primer/navigation/tab_component.rb +3 -157
- data/app/components/primer/truncate.rb +1 -1
- data/lib/primer/deprecations.yml +9 -0
- data/lib/primer/forms/dsl/text_field_input.rb +1 -1
- data/lib/primer/forms/primer_text_field.js +17 -6
- data/lib/primer/forms/primer_text_field.ts +15 -7
- data/lib/primer/forms/text_field.html.erb +3 -3
- data/lib/primer/view_components/version.rb +1 -1
- data/lib/primer/yard/component_manifest.rb +2 -1
- data/lib/tasks/docs.rake +1 -1
- data/previews/primer/alpha/action_list_preview.rb +41 -29
- 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.rb +34 -4
- 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 +64 -8
- data/static/audited_at.json +2 -1
- data/static/constants.json +20 -8
- data/static/previews.json +20 -5
- data/static/statuses.json +4 -3
- metadata +10 -8
- 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,7 +3,7 @@
|
|
3
3
|
module Primer
|
4
4
|
module Alpha
|
5
5
|
class ActionList
|
6
|
-
#
|
6
|
+
# Group heading rendered above the group contents.
|
7
7
|
class Divider < Primer::Component
|
8
8
|
DEFAULT_SCHEME = :subtle
|
9
9
|
SCHEME_MAPPINGS = {
|
@@ -17,7 +17,7 @@ module Primer
|
|
17
17
|
def initialize(scheme: DEFAULT_SCHEME, **system_arguments)
|
18
18
|
@system_arguments = system_arguments
|
19
19
|
@system_arguments[:tag] = :li
|
20
|
-
@system_arguments[:role] = :
|
20
|
+
@system_arguments[:role] = :presentation
|
21
21
|
@system_arguments[:'aria-hidden'] = true
|
22
22
|
@scheme = fetch_or_fallback(SCHEME_OPTIONS, scheme, DEFAULT_SCHEME)
|
23
23
|
@system_arguments[:classes] = class_names(
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<%= render(Primer::BaseComponent.new(**@system_arguments)) do %>
|
1
|
+
<%= render(Primer::BaseComponent.new(tag: :div, **@system_arguments)) do %>
|
2
2
|
<%= render(Primer::BaseComponent.new(tag: @tag, classes: "ActionList-sectionDivider-title", id: @list_id)) do %>
|
3
3
|
<%= @title %>
|
4
4
|
<% end %>
|
@@ -11,21 +11,27 @@ module Primer
|
|
11
11
|
:filled => "ActionList-sectionDivider--filled"
|
12
12
|
}.freeze
|
13
13
|
SCHEME_OPTIONS = SCHEME_MAPPINGS.keys.freeze
|
14
|
+
HEADING_MIN = 1
|
15
|
+
HEADING_MAX = 6
|
16
|
+
HEADING_LEVELS = (HEADING_MIN..HEADING_MAX).to_a.freeze
|
14
17
|
|
15
18
|
# @param list_id [String] The unique identifier of the sub list the heading belongs to. Used internally.
|
16
19
|
# @param title [String] Sub list title.
|
20
|
+
# @param heading_level [Integer] Heading level. Level 2 results in an `<h2>` tag, level 3 an `<h3>` tag, etc.
|
17
21
|
# @param subtitle [String] Optional sub list description.
|
18
22
|
# @param scheme [Symbol] Display a background color if scheme is `filled`.
|
19
|
-
# @param tag [
|
23
|
+
# @param tag [Integer] Semantic tag for the heading.
|
20
24
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
21
|
-
def initialize(list_id:, title:,
|
22
|
-
|
23
|
-
|
25
|
+
def initialize(list_id:, title:, heading_level: 3, scheme: DEFAULT_SCHEME, subtitle: nil, **system_arguments)
|
26
|
+
raise "Heading level must be between #{HEADING_MIN} and #{HEADING_MAX}" unless HEADING_LEVELS.include?(heading_level)
|
27
|
+
|
28
|
+
@heading_level = heading_level
|
29
|
+
@tag = :"h#{heading_level}"
|
30
|
+
@system_arguments = deny_tag_argument(**system_arguments)
|
24
31
|
@list_id = list_id
|
25
32
|
@title = title
|
26
33
|
@subtitle = subtitle
|
27
34
|
@scheme = fetch_or_fallback(SCHEME_OPTIONS, scheme, DEFAULT_SCHEME)
|
28
|
-
@system_arguments[:tag] = :li
|
29
35
|
@system_arguments[:classes] = class_names(
|
30
36
|
"ActionList-sectionDivider",
|
31
37
|
SCHEME_MAPPINGS[@scheme],
|
@@ -84,12 +84,16 @@ module Primer
|
|
84
84
|
# A button rendered after the trailing icon that can be used to show a menu, activate
|
85
85
|
# a dialog, etc.
|
86
86
|
#
|
87
|
-
# @param show_on_hover [Boolean] Whether or not to show the button when the list item is hovered. If `true`, the button will be invisible until hovered. If `false`, the button will always be visible. Defaults to `false`.
|
88
87
|
# @param system_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Beta::IconButton) %>.
|
89
|
-
renders_one :trailing_action, lambda {
|
90
|
-
|
88
|
+
renders_one :trailing_action, lambda { |**system_arguments|
|
89
|
+
Primer::Beta::IconButton.new(
|
90
|
+
classes: class_names(
|
91
|
+
system_arguments[:classes],
|
92
|
+
"ActionListItem-trailingAction"
|
93
|
+
),
|
91
94
|
|
92
|
-
|
95
|
+
**system_arguments
|
96
|
+
)
|
93
97
|
}
|
94
98
|
|
95
99
|
# `Tooltip` that appears on mouse hover or keyboard focus over the trailing action button. Use tooltips sparingly and as
|
@@ -112,7 +116,7 @@ module Primer
|
|
112
116
|
# @private
|
113
117
|
renders_one :private_content
|
114
118
|
|
115
|
-
attr_reader :list, :href, :active, :disabled, :parent
|
119
|
+
attr_reader :id, :list, :href, :active, :disabled, :parent
|
116
120
|
|
117
121
|
# Whether or not this item is active.
|
118
122
|
#
|
@@ -150,7 +154,7 @@ module Primer
|
|
150
154
|
parent: nil,
|
151
155
|
truncate_label: false,
|
152
156
|
href: nil,
|
153
|
-
role:
|
157
|
+
role: nil,
|
154
158
|
size: DEFAULT_SIZE,
|
155
159
|
scheme: DEFAULT_SCHEME,
|
156
160
|
disabled: false,
|
@@ -167,7 +171,6 @@ module Primer
|
|
167
171
|
@truncate_label = truncate_label
|
168
172
|
@disabled = disabled
|
169
173
|
@active = active
|
170
|
-
@trailing_action_on_hover = false
|
171
174
|
@id = id
|
172
175
|
@system_arguments = system_arguments
|
173
176
|
@content_arguments = content_arguments
|
@@ -184,7 +187,7 @@ module Primer
|
|
184
187
|
"ActionListItem"
|
185
188
|
)
|
186
189
|
|
187
|
-
@system_arguments[:role] = role
|
190
|
+
@system_arguments[:role] = role if role
|
188
191
|
|
189
192
|
@system_arguments[:aria] ||= {}
|
190
193
|
@system_arguments[:aria][:disabled] = "true" if @disabled
|
@@ -209,12 +212,14 @@ module Primer
|
|
209
212
|
SIZE_MAPPINGS[@size]
|
210
213
|
)
|
211
214
|
|
212
|
-
|
213
|
-
@
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
215
|
+
unless @content_arguments[:tag]
|
216
|
+
if @href && !@disabled
|
217
|
+
@content_arguments[:tag] = :a
|
218
|
+
@content_arguments[:href] = @href
|
219
|
+
else
|
220
|
+
@content_arguments[:tag] = :button
|
221
|
+
@content_arguments[:onclick] = on_click if on_click
|
222
|
+
end
|
218
223
|
end
|
219
224
|
|
220
225
|
@description_wrapper_arguments = {
|
@@ -231,7 +236,6 @@ module Primer
|
|
231
236
|
@system_arguments[:classes] = class_names(
|
232
237
|
@system_arguments[:classes],
|
233
238
|
"ActionListItem--withActions" => trailing_action.present?,
|
234
|
-
"ActionListItem--trailingActionHover" => @trailing_action_on_hover,
|
235
239
|
"ActionListItem--navActive" => active?
|
236
240
|
)
|
237
241
|
|
@@ -1,15 +1,14 @@
|
|
1
|
-
<%= render(Primer::BaseComponent.new(tag: :
|
1
|
+
<%= render(Primer::BaseComponent.new(tag: :div)) do %>
|
2
2
|
<% if heading %>
|
3
3
|
<%= heading %>
|
4
4
|
<% end %>
|
5
|
-
<%= render(Primer::BaseComponent.new(tag: :
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
<% end %>
|
11
|
-
<%= item %>
|
5
|
+
<%= render(Primer::BaseComponent.new(tag: :ul, **@system_arguments)) do %>
|
6
|
+
<% items.each_with_index do |item, index| %>
|
7
|
+
<%# the conditions here make sure two dividers are never rendered one after the other %>
|
8
|
+
<% if index > 0 && @show_dividers && !item.is_a?(Divider) && !items[index - 1].is_a?(Divider) %>
|
9
|
+
<%= render(Primer::Alpha::ActionList::Divider.new) %>
|
12
10
|
<% end %>
|
11
|
+
<%= item %>
|
13
12
|
<% end %>
|
14
13
|
<% end %>
|
15
14
|
<% end %>
|
@@ -48,6 +48,15 @@ module Primer
|
|
48
48
|
end
|
49
49
|
}
|
50
50
|
|
51
|
+
# Adds a divider to the list of items.
|
52
|
+
#
|
53
|
+
# @param system_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Alpha::ActionList::Divider) %>.
|
54
|
+
def with_divider(**system_arguments, &block)
|
55
|
+
# This is a giant hack that should be removed when :items can be converted into a polymorphic slot.
|
56
|
+
# This feature needs to land in view_component first: https://github.com/ViewComponent/view_component/pull/1652
|
57
|
+
set_slot(:items, { renderable: Divider, collection: true }, **system_arguments, &block)
|
58
|
+
end
|
59
|
+
|
51
60
|
# @param role [Boolean] ARIA role describing the function of the list. listbox and menu are a common values.
|
52
61
|
# @param item_classes [String] Additional CSS classes to attach to items.
|
53
62
|
# @param scheme [Symbol] <%= one_of(Primer::Alpha::ActionList::SCHEME_OPTIONS) %>. `inset` children are offset (vertically and horizontally) from list edges. `full` (default) children are flush (vertically and horizontally) with list edges.
|
@@ -61,10 +70,10 @@ module Primer
|
|
61
70
|
**system_arguments
|
62
71
|
)
|
63
72
|
@id = self.class.generate_id
|
64
|
-
@role = role
|
65
73
|
|
66
74
|
@system_arguments = system_arguments
|
67
75
|
@system_arguments[:tag] = :ul
|
76
|
+
@system_arguments[:role] = role
|
68
77
|
@item_classes = item_classes
|
69
78
|
@scheme = fetch_or_fallback(SCHEME_OPTIONS, scheme, DEFAULT_SCHEME)
|
70
79
|
@show_dividers = show_dividers
|
@@ -72,7 +81,6 @@ module Primer
|
|
72
81
|
SCHEME_MAPPINGS[@scheme],
|
73
82
|
system_arguments[:classes],
|
74
83
|
"ActionListWrap",
|
75
|
-
"ActionListWrap--subGroup",
|
76
84
|
"ActionListWrap--divided" => @show_dividers
|
77
85
|
)
|
78
86
|
|
@@ -81,18 +89,15 @@ module Primer
|
|
81
89
|
|
82
90
|
# @private
|
83
91
|
def before_render
|
92
|
+
aria_label = aria(:label, @system_arguments)
|
93
|
+
aria_labelledby = aria(:labelledby, @system_arguments)
|
94
|
+
|
84
95
|
if heading.present?
|
85
96
|
@system_arguments[:"aria-labelledby"] = @id
|
86
|
-
|
87
|
-
|
97
|
+
raise ArgumentError, "An aria-label should not be provided if a heading is present" if aria_label.present?
|
98
|
+
elsif aria_label.blank? && aria_labelledby.blank?
|
99
|
+
raise ArgumentError, "An aria-label, aria-labelledby, or heading must be provided"
|
88
100
|
end
|
89
|
-
|
90
|
-
return if items.blank?
|
91
|
-
|
92
|
-
@list_wrapper_arguments[:classes] = class_names(
|
93
|
-
@list_wrapper_arguments[:classes],
|
94
|
-
"ActionListItem--hasSubItem"
|
95
|
-
)
|
96
101
|
end
|
97
102
|
|
98
103
|
# @private
|
@@ -6,10 +6,10 @@ module Primer
|
|
6
6
|
# A logical grouping of navigation links with an optional heading.
|
7
7
|
#
|
8
8
|
# See <%= link_to_component(Primer::Alpha::NavList) %> for usage examples.
|
9
|
-
class
|
10
|
-
# A special "show more" list item that appears at the bottom of the
|
9
|
+
class Group < ActionList
|
10
|
+
# A special "show more" list item that appears at the bottom of the group. Clicking
|
11
11
|
# the item will fetch the next page of results from the URL passed in the `src` argument
|
12
|
-
# and append the resulting chunk of HTML to the
|
12
|
+
# and append the resulting chunk of HTML to the group.
|
13
13
|
#
|
14
14
|
# @param src [String] The URL to query for additional pages of list items.
|
15
15
|
# @param pages [Integer] The total number of pages in the result set.
|
@@ -51,14 +51,14 @@ module Primer
|
|
51
51
|
super(**@system_arguments)
|
52
52
|
end
|
53
53
|
|
54
|
-
# Cause this
|
54
|
+
# Cause this group to show its list of sub items when rendered.
|
55
55
|
# :nocov:
|
56
56
|
def expand!
|
57
57
|
@expanded = true
|
58
58
|
end
|
59
59
|
# :nocov:
|
60
60
|
|
61
|
-
# The items contained within this
|
61
|
+
# The items contained within this group.
|
62
62
|
#
|
63
63
|
# @return [Array<Primer::Alpha::ActionList::Item>]
|
64
64
|
def items
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<% with_private_content do %>
|
2
2
|
<% unless items.empty? %>
|
3
3
|
<% capture do %>
|
4
|
-
<%= render(Primer::BaseComponent.new(tag: :ul, **@sub_list_arguments)) do %>
|
4
|
+
<%= render(Primer::BaseComponent.new(tag: :ul, role: :list, **@sub_list_arguments)) do %>
|
5
5
|
<% items.each do |item| %>
|
6
6
|
<%= item %>
|
7
7
|
<% end %>
|
@@ -47,6 +47,10 @@ module Primer
|
|
47
47
|
)
|
48
48
|
}
|
49
49
|
|
50
|
+
@list = system_arguments[:list]
|
51
|
+
|
52
|
+
@sub_list_arguments["data-action"] = "keydown:#{@list.custom_element_name}#handleItemWithSubItemKeydown" if @list
|
53
|
+
|
50
54
|
overrides = { "data-item-id": @selected_by_ids.join(" ") }
|
51
55
|
|
52
56
|
super(**system_arguments, **overrides)
|
@@ -79,9 +83,19 @@ module Primer
|
|
79
83
|
|
80
84
|
return if items.blank?
|
81
85
|
|
86
|
+
@sub_list_arguments[:aria] = merge_aria(
|
87
|
+
@sub_list_arguments,
|
88
|
+
{ aria: { labelledby: id } }
|
89
|
+
)
|
90
|
+
|
91
|
+
raise ArgumentError, "Items with sub-items cannot have hrefs" if href.present?
|
92
|
+
|
82
93
|
@content_arguments[:tag] = :button
|
83
94
|
@content_arguments[:"aria-expanded"] = @expanded.to_s
|
84
|
-
@content_arguments[:"data-action"] = "
|
95
|
+
@content_arguments[:"data-action"] = "
|
96
|
+
click:#{@list.custom_element_name}#handleItemWithSubItemClick
|
97
|
+
keydown:#{@list.custom_element_name}#handleItemWithSubItemKeydown
|
98
|
+
"
|
85
99
|
|
86
100
|
with_private_trailing_action_icon(:"chevron-down", classes: "ActionListItem-collapseIcon")
|
87
101
|
|
@@ -18,6 +18,7 @@ export declare class NavListElement extends HTMLElement {
|
|
18
18
|
collapseItem(item: HTMLElement): void;
|
19
19
|
itemIsExpanded(item: HTMLElement | null): boolean;
|
20
20
|
handleItemWithSubItemClick(e: Event): void;
|
21
|
+
handleItemWithSubItemKeydown(e: KeyboardEvent): void;
|
21
22
|
private showMore;
|
22
23
|
private setShowMoreItemState;
|
23
24
|
}
|
@@ -1,10 +1,10 @@
|
|
1
|
-
<%= render(Primer::BaseComponent.new(tag: :
|
2
|
-
|
3
|
-
<%
|
4
|
-
|
1
|
+
<%= render(Primer::BaseComponent.new(tag: :nav, **@system_arguments)) do %>
|
2
|
+
<nav-list>
|
3
|
+
<% groups.each_with_index do |group, index| %>
|
4
|
+
<% if index > 0 %>
|
5
|
+
<%= render(Primer::Alpha::ActionList::Divider.new) %>
|
6
|
+
<% end %>
|
7
|
+
<%= group %>
|
5
8
|
<% end %>
|
6
|
-
|
7
|
-
<%= section %>
|
8
|
-
</li>
|
9
|
-
<% end %>
|
9
|
+
</nav-list>
|
10
10
|
<% end %>
|
@@ -82,6 +82,7 @@ let NavListElement = class NavListElement extends HTMLElement {
|
|
82
82
|
var _a;
|
83
83
|
(_a = item.nextElementSibling) === null || _a === void 0 ? void 0 : _a.setAttribute('data-hidden', '');
|
84
84
|
item.setAttribute('aria-expanded', 'false');
|
85
|
+
item.focus();
|
85
86
|
}
|
86
87
|
itemIsExpanded(item) {
|
87
88
|
if ((item === null || item === void 0 ? void 0 : item.tagName) === 'A') {
|
@@ -105,6 +106,26 @@ let NavListElement = class NavListElement extends HTMLElement {
|
|
105
106
|
}
|
106
107
|
e.stopPropagation();
|
107
108
|
}
|
109
|
+
// collapse item
|
110
|
+
handleItemWithSubItemKeydown(e) {
|
111
|
+
const el = e.currentTarget;
|
112
|
+
if (!(el instanceof HTMLElement))
|
113
|
+
return;
|
114
|
+
let button = el.closest('button');
|
115
|
+
if (!button) {
|
116
|
+
const button_id = el.getAttribute('aria-labelledby');
|
117
|
+
if (button_id) {
|
118
|
+
button = document.getElementById(button_id);
|
119
|
+
}
|
120
|
+
else {
|
121
|
+
return;
|
122
|
+
}
|
123
|
+
}
|
124
|
+
if (this.itemIsExpanded(button) && e.key === 'Escape') {
|
125
|
+
this.collapseItem(button);
|
126
|
+
}
|
127
|
+
e.stopPropagation();
|
128
|
+
}
|
108
129
|
async showMore(e) {
|
109
130
|
var _a, _b;
|
110
131
|
e.preventDefault();
|
@@ -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,13 +91,13 @@ module Primer
|
|
91
91
|
# @example Trailing action
|
92
92
|
#
|
93
93
|
# <%= render(Primer::Alpha::NavList.new) do |component| %>
|
94
|
-
# <% component.
|
95
|
-
# <%
|
96
|
-
# <%
|
97
|
-
# <% item.with_trailing_action(
|
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
|
+
# <% item.with_trailing_action(icon: "plus", "aria-label": "Add new food", size: :medium) %>
|
98
98
|
# <% end %>
|
99
|
-
# <%
|
100
|
-
# <% item.with_trailing_action(
|
99
|
+
# <% group.with_item(label: "Slurm", selected_by_ids: :slurm, href: "/foods/slurm") do |item| %>
|
100
|
+
# <% item.with_trailing_action(icon: "plus", "aria-label": "Add new food", size: :medium) %>
|
101
101
|
# <% end %>
|
102
102
|
# <% end %>
|
103
103
|
# <% 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
|