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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/app/assets/javascripts/primer_view_components.js +1 -1
  4. data/app/assets/javascripts/primer_view_components.js.map +1 -1
  5. data/app/assets/styles/primer_view_components.css +1 -1
  6. data/app/assets/styles/primer_view_components.css.map +1 -1
  7. data/app/components/primer/alpha/action_list/action-list-selection.pcss +92 -0
  8. data/app/components/primer/alpha/action_list/action-list.pcss +620 -0
  9. data/app/components/primer/alpha/action_list/divider.rb +35 -0
  10. data/app/components/primer/alpha/action_list/heading.html.erb +8 -0
  11. data/app/components/primer/alpha/action_list/heading.rb +38 -0
  12. data/app/components/primer/alpha/action_list/item.html.erb +39 -0
  13. data/app/components/primer/alpha/action_list/item.rb +230 -0
  14. data/app/components/primer/alpha/action_list.html.erb +15 -0
  15. data/app/components/primer/alpha/action_list.rb +112 -0
  16. data/app/components/primer/alpha/dialog/header.rb +1 -1
  17. data/app/components/primer/alpha/nav_list/item.html.erb +13 -0
  18. data/app/components/primer/alpha/nav_list/item.rb +89 -0
  19. data/app/components/primer/alpha/nav_list/section.html.erb +3 -0
  20. data/app/components/primer/alpha/nav_list/section.rb +88 -0
  21. data/app/components/primer/alpha/nav_list.d.ts +25 -0
  22. data/app/components/primer/alpha/nav_list.html.erb +10 -0
  23. data/app/components/primer/alpha/nav_list.js +130 -0
  24. data/app/components/primer/alpha/nav_list.rb +112 -0
  25. data/app/components/primer/alpha/nav_list.ts +129 -0
  26. data/app/components/primer/primer.d.ts +1 -0
  27. data/app/components/primer/primer.js +1 -0
  28. data/app/components/primer/primer.pcss +1 -0
  29. data/app/components/primer/primer.ts +1 -0
  30. data/lib/postcss_mixins/activeIndicatorLine.pcss +11 -0
  31. data/lib/primer/view_components/version.rb +1 -1
  32. data/lib/tasks/docs.rake +51 -22
  33. data/lib/yard/docs_helper.rb +3 -3
  34. data/static/arguments.json +267 -3
  35. data/static/audited_at.json +7 -0
  36. data/static/constants.json +76 -0
  37. data/static/statuses.json +7 -0
  38. metadata +21 -4
  39. data/app/components/primer/experimental/action_bar.d.ts +0 -14
  40. 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] = :header
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,3 @@
1
+ <nav-list>
2
+ <%= render_parent %>
3
+ </nav-list>
@@ -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 %>