primer_view_components 0.0.96 → 0.0.97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 %>
|