primer_view_components 0.0.96 → 0.0.97
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -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/action-list-selection.pcss +92 -0
- data/app/components/primer/alpha/action_list/action-list.pcss +620 -0
- data/app/components/primer/alpha/action_list/divider.rb +35 -0
- data/app/components/primer/alpha/action_list/heading.html.erb +8 -0
- data/app/components/primer/alpha/action_list/heading.rb +38 -0
- data/app/components/primer/alpha/action_list/item.html.erb +39 -0
- data/app/components/primer/alpha/action_list/item.rb +230 -0
- data/app/components/primer/alpha/action_list.html.erb +15 -0
- data/app/components/primer/alpha/action_list.rb +112 -0
- data/app/components/primer/alpha/dialog/header.rb +1 -1
- data/app/components/primer/alpha/nav_list/item.html.erb +13 -0
- data/app/components/primer/alpha/nav_list/item.rb +89 -0
- data/app/components/primer/alpha/nav_list/section.html.erb +3 -0
- data/app/components/primer/alpha/nav_list/section.rb +88 -0
- data/app/components/primer/alpha/nav_list.d.ts +25 -0
- data/app/components/primer/alpha/nav_list.html.erb +10 -0
- data/app/components/primer/alpha/nav_list.js +130 -0
- data/app/components/primer/alpha/nav_list.rb +112 -0
- data/app/components/primer/alpha/nav_list.ts +129 -0
- data/app/components/primer/primer.d.ts +1 -0
- data/app/components/primer/primer.js +1 -0
- data/app/components/primer/primer.pcss +1 -0
- data/app/components/primer/primer.ts +1 -0
- data/lib/postcss_mixins/activeIndicatorLine.pcss +11 -0
- data/lib/primer/view_components/version.rb +1 -1
- data/lib/tasks/docs.rake +51 -22
- data/lib/yard/docs_helper.rb +3 -3
- data/static/arguments.json +267 -3
- data/static/audited_at.json +7 -0
- data/static/constants.json +76 -0
- data/static/statuses.json +7 -0
- metadata +21 -4
- data/app/components/primer/experimental/action_bar.d.ts +0 -14
- data/app/components/primer/experimental/action_bar.js +0 -141
@@ -0,0 +1,39 @@
|
|
1
|
+
<%= render(Primer::BaseComponent.new(tag: :li, **@system_arguments)) do %>
|
2
|
+
<%= render(Primer::BaseComponent.new(**@content_arguments)) do %>
|
3
|
+
<% if private_leading_action_icon %>
|
4
|
+
<span class="ActionListItem-visual ActionListItem-action--leading">
|
5
|
+
<%= private_leading_action_icon %>
|
6
|
+
</span>
|
7
|
+
<% end %>
|
8
|
+
<% if leading_visual %>
|
9
|
+
<span class="ActionListItem-visual ActionListItem-visual--leading">
|
10
|
+
<%= leading_visual %>
|
11
|
+
</span>
|
12
|
+
<% end %>
|
13
|
+
<%= render(Primer::ConditionalWrapper.new(condition: description?, tag: :span, **@description_wrapper_arguments)) do %>
|
14
|
+
<%= render(Primer::BaseComponent.new(tag: :span, **@label_arguments)) do %>
|
15
|
+
<%= @label %>
|
16
|
+
<% end %>
|
17
|
+
<% if description? %>
|
18
|
+
<span class="ActionListItem-description">
|
19
|
+
<%= description %>
|
20
|
+
</span>
|
21
|
+
<% end %>
|
22
|
+
<% end %>
|
23
|
+
<% if trailing_visual %>
|
24
|
+
<span class="ActionListItem-visual ActionListItem-visual--trailing">
|
25
|
+
<%= trailing_visual %>
|
26
|
+
</span>
|
27
|
+
<% end %>
|
28
|
+
<% if private_trailing_action_icon %>
|
29
|
+
<span class="ActionListItem-visual ActionListItem-action--trailing">
|
30
|
+
<%= private_trailing_action_icon %>
|
31
|
+
</span>
|
32
|
+
<% end %>
|
33
|
+
<% end %>
|
34
|
+
<%= tooltip %>
|
35
|
+
<% if trailing_action %>
|
36
|
+
<%= trailing_action %>
|
37
|
+
<% end %>
|
38
|
+
<%= private_content %>
|
39
|
+
<% end %>
|
@@ -0,0 +1,230 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Primer
|
4
|
+
module Alpha
|
5
|
+
class ActionList
|
6
|
+
# An individual `ActionList` item. Items can optionally include leading and/or trailing visuals,
|
7
|
+
# such as icons, avatars, and counters.
|
8
|
+
class Item < Primer::Component
|
9
|
+
DEFAULT_SIZE = :medium
|
10
|
+
SIZE_MAPPINGS = {
|
11
|
+
DEFAULT_SIZE => nil,
|
12
|
+
:large => "ActionListContent--sizeLarge",
|
13
|
+
:xlarge => "ActionListContent--sizeXLarge"
|
14
|
+
}.freeze
|
15
|
+
SIZE_OPTIONS = SIZE_MAPPINGS.keys.freeze
|
16
|
+
|
17
|
+
DEFAULT_DESCRIPTION_SCHEME = :block
|
18
|
+
DESCRIPTION_SCHEME_MAPPINGS = {
|
19
|
+
:inline => "ActionListItem-descriptionWrap--inline",
|
20
|
+
DEFAULT_DESCRIPTION_SCHEME => "ActionListItem-descriptionWrap"
|
21
|
+
}.freeze
|
22
|
+
DESCRIPTION_SCHEME_OPTIONS = DESCRIPTION_SCHEME_MAPPINGS.keys.freeze
|
23
|
+
|
24
|
+
DEFAULT_SCHEME = :default
|
25
|
+
SCHEME_MAPPINGS = {
|
26
|
+
DEFAULT_SCHEME => nil,
|
27
|
+
:danger => "ActionListItem--danger"
|
28
|
+
}.freeze
|
29
|
+
SCHEME_OPTIONS = SCHEME_MAPPINGS.keys.freeze
|
30
|
+
|
31
|
+
# Description content that complements the item's label. See `ActionList`'s `description_scheme` argument
|
32
|
+
# for layout options.
|
33
|
+
renders_one :description
|
34
|
+
|
35
|
+
# An icon or avatar that will render to the left of the label.
|
36
|
+
#
|
37
|
+
# To render an icon, call the `with_leading_visual_icon` method, which accepts the arguments accepted by <%= link_to_component(Primer::OcticonComponent) %>.
|
38
|
+
#
|
39
|
+
# To render an avatar, call the `with_leading_visual_avatar` method, which accepts the arguments accepted by <%= link_to_component(Primer::Beta::Avatar) %>.
|
40
|
+
renders_one :leading_visual, types: {
|
41
|
+
icon: Primer::OcticonComponent,
|
42
|
+
avatar: ->(**kwargs) { Primer::Beta::Avatar.new(**{ **kwargs, size: 16 }) }
|
43
|
+
}
|
44
|
+
|
45
|
+
# Used internally.
|
46
|
+
#
|
47
|
+
# @private
|
48
|
+
renders_one :private_leading_action_icon, Primer::OcticonComponent
|
49
|
+
|
50
|
+
# An icon, label, counter, or text to render to the right of the label.
|
51
|
+
#
|
52
|
+
# To render an icon, call the `with_leading_visual_icon` method, which accepts the arguments accepted by <%= link_to_component(Primer::OcticonComponent) %>.
|
53
|
+
#
|
54
|
+
# To render a label, call the `with_leading_visual_label` method, which accepts the arguments accepted by <%= link_to_component(Primer::LabelComponent) %>.
|
55
|
+
#
|
56
|
+
# To render a counter, call the `with_leading_visual_counter` method, which accepts the arguments accepted by <%= link_to_component(Primer::CounterComponent) %>.
|
57
|
+
#
|
58
|
+
# To render text, call the `with_leading_visual_text` method and pass a block that returns a string. Eg:
|
59
|
+
# ```ruby
|
60
|
+
# with_leading_visual_text { "Text here" }`
|
61
|
+
# ```
|
62
|
+
renders_one :trailing_visual, types: {
|
63
|
+
icon: Primer::OcticonComponent,
|
64
|
+
label: Primer::LabelComponent,
|
65
|
+
counter: Primer::CounterComponent,
|
66
|
+
text: ->(text) { text }
|
67
|
+
}
|
68
|
+
|
69
|
+
# Used internally.
|
70
|
+
#
|
71
|
+
# @private
|
72
|
+
renders_one :private_trailing_action_icon, Primer::OcticonComponent
|
73
|
+
|
74
|
+
# A button rendered after the trailing icon that can be used to show a menu, activate
|
75
|
+
# a dialog, etc.
|
76
|
+
#
|
77
|
+
# @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`.
|
78
|
+
# @param system_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Beta::IconButton) %>.
|
79
|
+
renders_one :trailing_action, lambda { |show_on_hover: false, **system_arguments|
|
80
|
+
@trailing_action_on_hover = show_on_hover
|
81
|
+
|
82
|
+
Primer::Beta::IconButton.new(scheme: :invisible, classes: ["ActionListItem-trailingAction"], **system_arguments)
|
83
|
+
}
|
84
|
+
|
85
|
+
# `Tooltip` that appears on mouse hover or keyboard focus over the trailing action button. Use tooltips sparingly and as
|
86
|
+
# a last resort. **Important:** This tooltip defaults to `type: :description`. In a few scenarios, `type: :label` may be
|
87
|
+
# more appropriate. Consult the <%= link_to_component(Primer::Alpha::Tooltip) %> documentation for more information.
|
88
|
+
#
|
89
|
+
# @param type [Symbol] (:description) <%= one_of(Primer::Alpha::Tooltip::TYPE_OPTIONS) %>
|
90
|
+
# @param system_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Alpha::Tooltip) %>.
|
91
|
+
renders_one :tooltip, lambda { |**system_arguments|
|
92
|
+
raise ArgumentError, "Buttons with a tooltip must have a unique `id` set on the `Button`." if @id.blank? && !Rails.env.production?
|
93
|
+
|
94
|
+
system_arguments[:for_id] = @id
|
95
|
+
system_arguments[:type] ||= :description
|
96
|
+
|
97
|
+
Primer::Alpha::Tooltip.new(**system_arguments)
|
98
|
+
}
|
99
|
+
|
100
|
+
# Used internally.
|
101
|
+
#
|
102
|
+
# @private
|
103
|
+
renders_one :private_content
|
104
|
+
|
105
|
+
attr_reader :list, :active, :disabled, :parent
|
106
|
+
|
107
|
+
# Whether or not this item is active.
|
108
|
+
#
|
109
|
+
# @return [Boolean]
|
110
|
+
alias active? active
|
111
|
+
|
112
|
+
# Whether or not this item is disabled.
|
113
|
+
#
|
114
|
+
# @return [Boolean]
|
115
|
+
alias disabled? disabled
|
116
|
+
|
117
|
+
# @param list [Primer::Alpha::ActionList] The list that contains this item. Used internally.
|
118
|
+
# @param parent [Primer::Alpha::ActionList::Item] This item's parent item. `nil` if this item is at the root. Used internally.
|
119
|
+
# @param label [String] Item label.
|
120
|
+
# @param label_classes [String] CSS classes that will be added to the label.
|
121
|
+
# @param truncate_label [Boolean] Truncate label with ellipsis.
|
122
|
+
# @param href [String] Link URL.
|
123
|
+
# @param role [String] ARIA role describing the function of the item.
|
124
|
+
# @param size [Symbol] Controls block sizing of the item.
|
125
|
+
# @param scheme [Symbol] Controls color/style based on behavior.
|
126
|
+
# @param disabled [Boolean] Disabled items are not clickable and visually dim.
|
127
|
+
# @param description_scheme [Symbol] Display description inline with label, or block on the next line.
|
128
|
+
# @param active [Boolean] Sets an active state on navigational items.
|
129
|
+
# @param on_click [String] JavaScript to execute when the item is clicked.
|
130
|
+
# @param id [String] Used internally.
|
131
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
132
|
+
def initialize(
|
133
|
+
list:,
|
134
|
+
label:,
|
135
|
+
label_classes: nil,
|
136
|
+
parent: nil,
|
137
|
+
truncate_label: false,
|
138
|
+
href: nil,
|
139
|
+
role: :listitem,
|
140
|
+
size: DEFAULT_SIZE,
|
141
|
+
scheme: DEFAULT_SCHEME,
|
142
|
+
disabled: false,
|
143
|
+
description_scheme: DEFAULT_DESCRIPTION_SCHEME,
|
144
|
+
active: false,
|
145
|
+
on_click: nil,
|
146
|
+
id: SecureRandom.hex,
|
147
|
+
**system_arguments
|
148
|
+
)
|
149
|
+
@list = list
|
150
|
+
@parent = parent
|
151
|
+
@label = label
|
152
|
+
@href = href
|
153
|
+
@truncate_label = truncate_label
|
154
|
+
@disabled = disabled
|
155
|
+
@active = active
|
156
|
+
@trailing_action_on_hover = false
|
157
|
+
@id = id
|
158
|
+
@system_arguments = system_arguments
|
159
|
+
|
160
|
+
@size = fetch_or_fallback(SIZE_OPTIONS, size, DEFAULT_SIZE)
|
161
|
+
@scheme = fetch_or_fallback(SCHEME_OPTIONS, scheme, DEFAULT_SCHEME)
|
162
|
+
@description_scheme = fetch_or_fallback(
|
163
|
+
DESCRIPTION_SCHEME_OPTIONS, description_scheme, DEFAULT_DESCRIPTION_SCHEME
|
164
|
+
)
|
165
|
+
|
166
|
+
@system_arguments[:classes] = class_names(
|
167
|
+
@system_arguments[:classes],
|
168
|
+
SCHEME_MAPPINGS[@scheme],
|
169
|
+
"ActionListItem",
|
170
|
+
"ActionListItem--navActive" => @active
|
171
|
+
)
|
172
|
+
|
173
|
+
@system_arguments[:role] = role
|
174
|
+
|
175
|
+
@system_arguments[:aria] ||= {}
|
176
|
+
@system_arguments[:aria][:disabled] = "true" if @disabled
|
177
|
+
|
178
|
+
@label_arguments = {
|
179
|
+
classes: class_names(
|
180
|
+
label_classes,
|
181
|
+
"ActionListItem-label",
|
182
|
+
"ActionListItem-label--truncate" => @truncate_label
|
183
|
+
)
|
184
|
+
}
|
185
|
+
|
186
|
+
@content_arguments = {
|
187
|
+
id: @id,
|
188
|
+
classes: class_names(
|
189
|
+
"ActionListContent",
|
190
|
+
SIZE_MAPPINGS[@size]
|
191
|
+
)
|
192
|
+
}
|
193
|
+
|
194
|
+
if @href && !@disabled
|
195
|
+
@content_arguments[:tag] = :a
|
196
|
+
@content_arguments[:href] = @href
|
197
|
+
else
|
198
|
+
@content_arguments[:tag] = :span
|
199
|
+
@content_arguments[:onclick] = on_click if on_click
|
200
|
+
end
|
201
|
+
|
202
|
+
@description_wrapper_arguments = {
|
203
|
+
classes: class_names(
|
204
|
+
"ActionListItem-descriptionWrap",
|
205
|
+
DESCRIPTION_SCHEME_MAPPINGS[@description_scheme]
|
206
|
+
)
|
207
|
+
}
|
208
|
+
end
|
209
|
+
|
210
|
+
private
|
211
|
+
|
212
|
+
def before_render
|
213
|
+
@system_arguments[:classes] = class_names(
|
214
|
+
@system_arguments[:classes],
|
215
|
+
"ActionListItem--withActions" => trailing_action.present?,
|
216
|
+
"ActionListItem--trailingActionHover" => @trailing_action_on_hover
|
217
|
+
)
|
218
|
+
|
219
|
+
return unless leading_visual
|
220
|
+
|
221
|
+
@content_arguments[:classes] = class_names(
|
222
|
+
@content_arguments[:classes],
|
223
|
+
"ActionListContent--visual16" => leading_visual,
|
224
|
+
"ActionListContent--blockDescription" => description && @description_scheme == :block
|
225
|
+
)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<%= render(Primer::BaseComponent.new(tag: :ul, role: @role, classes: "ActionListWrap")) do %>
|
2
|
+
<% if heading %>
|
3
|
+
<%= heading %>
|
4
|
+
<% end %>
|
5
|
+
<%= render(Primer::BaseComponent.new(tag: :li, **@list_wrapper_arguments)) do %>
|
6
|
+
<%= render(Primer::BaseComponent.new(tag: :ul, **@system_arguments)) do %>
|
7
|
+
<% items.each_with_index do |item, index| %>
|
8
|
+
<% if index > 0 && @show_dividers %>
|
9
|
+
<%= render(Primer::Alpha::ActionList::Divider.new) %>
|
10
|
+
<% end %>
|
11
|
+
<%= item %>
|
12
|
+
<% end %>
|
13
|
+
<% end %>
|
14
|
+
<% end %>
|
15
|
+
<% end %>
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Primer
|
4
|
+
module Alpha
|
5
|
+
# An ActionList is a styled list of links. It acts as the base component for many
|
6
|
+
# other menu-type components, including `ActionMenu` and `SelectPanel`, as well as
|
7
|
+
# the navigational component `NavList`.
|
8
|
+
#
|
9
|
+
# Each item in an action list can be augmented by specifying corresponding leading
|
10
|
+
# and/or trailing visuals.
|
11
|
+
class ActionList < Primer::Component
|
12
|
+
status :alpha
|
13
|
+
|
14
|
+
DEFAULT_ROLE = :list
|
15
|
+
|
16
|
+
DEFAULT_SCHEME = :full
|
17
|
+
SCHEME_MAPPINGS = {
|
18
|
+
DEFAULT_SCHEME => nil,
|
19
|
+
:inset => "ActionListWrap--inset"
|
20
|
+
}.freeze
|
21
|
+
SCHEME_OPTIONS = SCHEME_MAPPINGS.keys.freeze
|
22
|
+
|
23
|
+
# @private
|
24
|
+
def self.custom_element_name
|
25
|
+
@custom_element_name ||= name.split("::").last.underscore.dasherize
|
26
|
+
end
|
27
|
+
|
28
|
+
# @private
|
29
|
+
def custom_element_name
|
30
|
+
self.class.custom_element_name
|
31
|
+
end
|
32
|
+
|
33
|
+
# Heading text rendered above the list of items.
|
34
|
+
#
|
35
|
+
# @param system_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Alpha::ActionList::Heading) %>.
|
36
|
+
renders_one :heading, lambda { |**system_arguments|
|
37
|
+
Heading.new(list_id: @id, **system_arguments)
|
38
|
+
}
|
39
|
+
|
40
|
+
# Items.
|
41
|
+
#
|
42
|
+
# @param system_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Alpha::ActionList::Item) %>.
|
43
|
+
renders_many :items, lambda { |**system_arguments|
|
44
|
+
build_item(**system_arguments).tap do |item|
|
45
|
+
will_add_item(item)
|
46
|
+
end
|
47
|
+
}
|
48
|
+
|
49
|
+
# @param role [Boolean] ARIA role describing the function of the list. listbox and menu are a common values.
|
50
|
+
# @param item_classes [String] Additional CSS classes to attach to items.
|
51
|
+
# @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.
|
52
|
+
# @param show_dividers [Boolean] Display a divider above each item in the list when it does not follow a header or divider.
|
53
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
54
|
+
def initialize(
|
55
|
+
role: DEFAULT_ROLE,
|
56
|
+
item_classes: nil,
|
57
|
+
scheme: DEFAULT_SCHEME,
|
58
|
+
show_dividers: false,
|
59
|
+
**system_arguments
|
60
|
+
)
|
61
|
+
@id = "action-list-#{SecureRandom.uuid}"
|
62
|
+
@role = role
|
63
|
+
|
64
|
+
@system_arguments = system_arguments
|
65
|
+
@system_arguments[:tag] = :ul
|
66
|
+
@item_classes = item_classes
|
67
|
+
@scheme = fetch_or_fallback(SCHEME_OPTIONS, scheme, DEFAULT_SCHEME)
|
68
|
+
@show_dividers = show_dividers
|
69
|
+
@system_arguments[:classes] = class_names(
|
70
|
+
SCHEME_MAPPINGS[@scheme],
|
71
|
+
system_arguments[:classes],
|
72
|
+
"ActionListWrap",
|
73
|
+
"ActionListWrap--subGroup",
|
74
|
+
"ActionListWrap--divided" => @show_dividers
|
75
|
+
)
|
76
|
+
|
77
|
+
@list_wrapper_arguments = {}
|
78
|
+
end
|
79
|
+
|
80
|
+
# @private
|
81
|
+
def before_render
|
82
|
+
return if @sub_group
|
83
|
+
|
84
|
+
if heading.present?
|
85
|
+
@system_arguments[:"aria-labelledby"] = @id
|
86
|
+
elsif aria(:label, @system_arguments).blank?
|
87
|
+
raise ArgumentError, "An aria-label or heading must be provided"
|
88
|
+
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
|
+
end
|
97
|
+
|
98
|
+
# @private
|
99
|
+
def build_item(**system_arguments)
|
100
|
+
system_arguments[:classes] = class_names(
|
101
|
+
@item_classes,
|
102
|
+
system_arguments[:classes]
|
103
|
+
)
|
104
|
+
|
105
|
+
ActionList::Item.new(list: self, **system_arguments)
|
106
|
+
end
|
107
|
+
|
108
|
+
# @private
|
109
|
+
def will_add_item(_item); end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -24,7 +24,7 @@ module Primer
|
|
24
24
|
@subtitle = subtitle
|
25
25
|
@visually_hide_title = visually_hide_title
|
26
26
|
@system_arguments = deny_tag_argument(**system_arguments)
|
27
|
-
@system_arguments[:tag] = :
|
27
|
+
@system_arguments[:tag] = :div
|
28
28
|
@system_arguments[:classes] = class_names(
|
29
29
|
"Overlay-header",
|
30
30
|
{ "Overlay-header--divided": show_divider },
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<% with_private_content do %>
|
2
|
+
<% unless items.empty? %>
|
3
|
+
<% capture do %>
|
4
|
+
<%= render(Primer::BaseComponent.new(tag: :ul, **@sub_list_arguments)) do %>
|
5
|
+
<% items.each do |item| %>
|
6
|
+
<%= item %>
|
7
|
+
<% end %>
|
8
|
+
<% end %>
|
9
|
+
<% end %>
|
10
|
+
<% end %>
|
11
|
+
<% end %>
|
12
|
+
|
13
|
+
<%= render_parent %>
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Primer
|
4
|
+
module Alpha
|
5
|
+
class NavList
|
6
|
+
# Items are rendered as styled links. They can optionally include leading and/or trailing visuals,
|
7
|
+
# such as icons, avatars, and counters. Items are selected by ID. IDs can be specified via the
|
8
|
+
# `selected_item_ids` argument, which accepts a list of valid IDs for the item. Items can also
|
9
|
+
# themselves contain sub items. Sub items are rendered collapsed by default.
|
10
|
+
class Item < Primer::Alpha::ActionList::Item
|
11
|
+
attr_reader :selected_by_ids, :sub_item
|
12
|
+
|
13
|
+
# @param system_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Alpha::ActionList::Item) %>.
|
14
|
+
renders_many :items, lambda { |**system_arguments|
|
15
|
+
raise "Items can only be nested 2 levels deep" if sub_item?
|
16
|
+
|
17
|
+
@list.build_item(parent: self, sub_item: true, **system_arguments).tap do |item|
|
18
|
+
@list.will_add_item(item)
|
19
|
+
|
20
|
+
if item.active?
|
21
|
+
@content_arguments[:classes] = class_names(
|
22
|
+
@content_arguments[:classes],
|
23
|
+
"ActionListContent--hasActiveSubItem"
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
}
|
28
|
+
|
29
|
+
# Whether or not this item is nested under a parent item.
|
30
|
+
#
|
31
|
+
# @return [Boolean]
|
32
|
+
alias sub_item? sub_item
|
33
|
+
|
34
|
+
# @param selected_item_id [Symbol] The ID of the currently selected list item. Used internally.
|
35
|
+
# @param selected_by_ids [Array<Symbol>] The list of IDs that select this item. In other words, if the `selected_item_id` attribute on the parent `NavList` is set to one of these IDs, the item will appear selected.
|
36
|
+
# @param expanded [Boolean] Whether this item shows (expands) or hides (collapses) its list of sub items.
|
37
|
+
# @param sub_item [Boolean] Whether or not this item is nested under a parent item. Used internally.
|
38
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
39
|
+
def initialize(selected_item_id: nil, selected_by_ids: [], sub_item: false, expanded: false, **system_arguments)
|
40
|
+
@selected_item_id = selected_item_id
|
41
|
+
@selected_by_ids = Array(selected_by_ids)
|
42
|
+
@expanded = expanded
|
43
|
+
@sub_item = sub_item
|
44
|
+
|
45
|
+
system_arguments[:classes] = class_names(
|
46
|
+
system_arguments[:classes],
|
47
|
+
"ActionListItem--subItem" => @sub_item
|
48
|
+
)
|
49
|
+
|
50
|
+
@sub_list_arguments = {
|
51
|
+
classes: class_names(
|
52
|
+
"ActionList",
|
53
|
+
"ActionList--subGroup"
|
54
|
+
)
|
55
|
+
}
|
56
|
+
|
57
|
+
overrides = { "data-item-id": @selected_by_ids.join(" ") }
|
58
|
+
overrides[:active] = @selected_by_ids.include?(@selected_item_id)
|
59
|
+
|
60
|
+
super(**system_arguments, **overrides)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Cause this item to show its list of sub items when rendered.
|
64
|
+
def expand!
|
65
|
+
@expanded = true
|
66
|
+
end
|
67
|
+
|
68
|
+
def before_render
|
69
|
+
super
|
70
|
+
|
71
|
+
raise "Cannot render a trailing visual for an item with subitems" if items.present? && trailing_visual.present?
|
72
|
+
|
73
|
+
return if items.blank?
|
74
|
+
|
75
|
+
@content_arguments[:tag] = :button
|
76
|
+
@content_arguments[:"aria-expanded"] = @expanded.to_s
|
77
|
+
@content_arguments[:"data-action"] = "click:#{@list.custom_element_name}#handleItemWithSubItemClick"
|
78
|
+
|
79
|
+
with_private_trailing_action_icon(:"chevron-down", classes: "ActionListItem-collapseIcon")
|
80
|
+
|
81
|
+
@system_arguments[:classes] = class_names(
|
82
|
+
@system_arguments[:classes],
|
83
|
+
"ActionListItem--hasSubItem"
|
84
|
+
)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Primer
|
4
|
+
module Alpha
|
5
|
+
class NavList
|
6
|
+
# A logical grouping of navigation links with an optional heading.
|
7
|
+
#
|
8
|
+
# See <%= link_to_component(Primer::Alpha::NavList) %> for usage examples.
|
9
|
+
class Section < ActionList
|
10
|
+
# A special "show more" list item that appears at the bottom of the section. Clicking
|
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 section.
|
13
|
+
#
|
14
|
+
# @param src [String] The URL to query for additional pages of list items.
|
15
|
+
# @param pages [Integer] The total number of pages in the result set.
|
16
|
+
# @param component_klass [Class] A component class to use instead of the default `Primer::Alpha::NavList::Item` class.
|
17
|
+
# @param system_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Alpha::NavList::Item) %>.
|
18
|
+
renders_one :show_more_item, lambda { |src:, pages:, component_klass: NavList::Item, **system_arguments|
|
19
|
+
system_arguments[:classes] = class_names(
|
20
|
+
@item_classes,
|
21
|
+
system_arguments[:classes]
|
22
|
+
)
|
23
|
+
system_arguments[:id] = "ActionList--showMoreItem"
|
24
|
+
system_arguments[:hidden] = true
|
25
|
+
system_arguments[:href] = "#"
|
26
|
+
system_arguments[:data] ||= {}
|
27
|
+
system_arguments[:data][:target] = "nav-list.showMoreItem"
|
28
|
+
system_arguments[:data][:action] = "click:nav-list#showMore"
|
29
|
+
system_arguments[:data][:"current-page"] = "1"
|
30
|
+
system_arguments[:data][:"total-pages"] = pages.to_s
|
31
|
+
system_arguments[:label_classes] = class_names(
|
32
|
+
system_arguments[:label_classes],
|
33
|
+
"color-fg-accent"
|
34
|
+
)
|
35
|
+
|
36
|
+
component_klass.new(list: self, src: src, **system_arguments)
|
37
|
+
}
|
38
|
+
|
39
|
+
# @private
|
40
|
+
def self.custom_element_name
|
41
|
+
"nav-list"
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param selected_item_id [Symbol] The ID of the currently selected item. Used internally.
|
45
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
46
|
+
def initialize(selected_item_id: nil, **system_arguments)
|
47
|
+
@system_arguments = system_arguments
|
48
|
+
@selected_item_id = selected_item_id
|
49
|
+
@system_arguments[:"data-target"] = "nav-list.list"
|
50
|
+
|
51
|
+
super(**@system_arguments)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Cause this section to show its list of sub items when rendered.
|
55
|
+
def expand!
|
56
|
+
@expanded = true
|
57
|
+
end
|
58
|
+
|
59
|
+
# The items contained within this section.
|
60
|
+
#
|
61
|
+
# @return [Array<Primer::Alpha::ActionList::Item>]
|
62
|
+
def items
|
63
|
+
[*super, show_more_item].tap(&:compact!)
|
64
|
+
end
|
65
|
+
|
66
|
+
# @!parse
|
67
|
+
# # Items.
|
68
|
+
# #
|
69
|
+
# # @param system_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Alpha::NavList::Item) %>.
|
70
|
+
# renders_many :items
|
71
|
+
|
72
|
+
# @private
|
73
|
+
def build_item(component_klass: NavList::Item, **system_arguments)
|
74
|
+
component_klass.new(
|
75
|
+
**system_arguments,
|
76
|
+
selected_item_id: @selected_item_id,
|
77
|
+
list: self
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
# @private
|
82
|
+
def will_add_item(item)
|
83
|
+
item.parent.expand! if item.active? && item.parent
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
declare class NavListElement extends HTMLElement {
|
2
|
+
list: HTMLElement;
|
3
|
+
showMoreItem: HTMLElement;
|
4
|
+
focusMarkers: HTMLElement[];
|
5
|
+
connectedCallback(): void;
|
6
|
+
get showMoreDisabled(): boolean;
|
7
|
+
set showMoreDisabled(value: boolean);
|
8
|
+
set currentPage(value: number);
|
9
|
+
get currentPage(): number;
|
10
|
+
get totalPages(): number;
|
11
|
+
get paginationSrc(): string;
|
12
|
+
expandItem(item: HTMLElement): void;
|
13
|
+
collapseItem(item: HTMLElement): void;
|
14
|
+
itemIsExpanded(item: HTMLElement | null): boolean;
|
15
|
+
handleItemWithSubItemClick(e: Event): void;
|
16
|
+
private showMore;
|
17
|
+
private setShowMoreItemState;
|
18
|
+
private parseHTML;
|
19
|
+
}
|
20
|
+
declare global {
|
21
|
+
interface Window {
|
22
|
+
NavListElement: typeof NavListElement;
|
23
|
+
}
|
24
|
+
}
|
25
|
+
export {};
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<%= render(Primer::BaseComponent.new(tag: :ul, **@system_arguments)) do %>
|
2
|
+
<% sections.each_with_index do |section, index| %>
|
3
|
+
<% if index > 0 %>
|
4
|
+
<%= render(Primer::Alpha::ActionList::Divider.new) %>
|
5
|
+
<% end %>
|
6
|
+
<li>
|
7
|
+
<%= section %>
|
8
|
+
</li>
|
9
|
+
<% end %>
|
10
|
+
<% end %>
|