Class: Primer::Alpha::ActionMenu

Inherits:
Component
  • Object
show all
Defined in:
app/components/primer/alpha/action_menu.rb,
app/components/primer/alpha/action_menu/list.rb,
app/components/primer/alpha/action_menu/menu.rb,
app/components/primer/alpha/action_menu/group.rb,
app/components/primer/alpha/action_menu/heading.rb,
app/components/primer/alpha/action_menu/sub_menu.rb,
app/components/primer/alpha/action_menu/list_wrapper.rb,
app/components/primer/alpha/action_menu/primary_menu.rb,
app/components/primer/alpha/action_menu/sub_menu_item.rb

Overview

ActionMenu is used for actions, navigation, to display secondary options, or single/multi select lists. They appear when users interact with buttons, actions, or other controls.

The only allowed elements for the ‘Item` components are: `:a`, `:button`, and `:clipboard-copy`. The default is `:button`.

### Select variants

While ‘ActionMenu`s default to a list of buttons that can link to other pages, copy text to the clipboard, etc, they also support `single` and `multiple` select variants. The single select variant allows a single item to be “selected” (i.e. marked “active”) when clicked, which will cause a check mark to appear to the left of the item text. When the `multiple` select variant is chosen, multiple items may be selected and check marks will appear next to each selected item.

Use the ‘select_variant:` option to control which variant the `ActionMenu` uses. For more information, see the documentation on supported arguments below.

### Dynamic labels

When using the ‘single` select variant, an optional label indicating the selected item can be displayed inside the menu button. Dynamic labels can also be prefixed with custom text.

Pass ‘dynamic_label: true` to enable dynamic label behavior, and pass `dynamic_label_prefix: “<string>”` to set a custom prefix. For more information, see the documentation on supported arguments below.

### ‘ActionMenu`s as form inputs

When using either the ‘single` or `multiple` select variants, `ActionMenu`s can be used as form inputs. They behave very similarly to how HTML `<select>` boxes behave, and play nicely with Rails’ built-in form mechanisms. Pass arguments via the ‘form_arguments:` argument, including the Rails form builder object and the name of the field:

“‘erb <% form_with(url: update_merge_strategy_path) do |f| %>

<%= render(Primer::Alpha::ActionMenu.new(form_arguments: { builder: f, name: "merge_strategy" })) do |menu| %>
  <% menu.with_item(label: "Fast forward", data: { value: "fast_forward" }) %>
  <% menu.with_item(label: "Recursive", data: { value: "recursive" }) %>
  <% menu.with_item(label: "Ours", data: { value: "ours" }) %>
  <% menu.with_item(label: "Theirs", data: { value: "theirs" }) %>
<% end %>

<% end %> “‘

The value of the ‘data: { value: … }` argument is sent to the server on submit, keyed using the name provided above (eg. `“merge_strategy”`). If no value is provided for an item, the value of that item is the item’s label. Here’s the corresponding ‘MergeStrategyController` that might be written to handle the form above:

“‘ruby class MergeStrategyController < ApplicationController

def update
  puts "You chose #{merge_strategy_params[:merge_strategy]}"
end

private

def merge_strategy_params
  params.permit(:merge_strategy)
end

end “‘

### ‘ActionMenu` items that submit forms

Whereas ‘ActionMenu` items normally permit navigation via `<a>` tags which make HTTP `get` requests, `ActionMenu` items also permit navigation via `POST` requests. To enable this behavior, include the `href:` argument as normal, but also pass the `form_arguments:` argument to the appropriate item:

“‘erb <%= render(Primer::Alpha::ActionMenu.new) do |menu| %>

<% menu.with_item(
  label: "Repository",
  href: update_repo_grouping_path,
  form_arguments: {
    method: :post,
    name: "group_by",
    value: "repository"
  }
) %>

<% end %> “‘

Make sure to specify ‘method: :post`, as the default is `:get`. When clicked, the list item will submit a POST request to the URL passed in the `href:` argument, including a parameter named `“group_by”` with a value of `“repository”`. If no value is given, the name, eg. `“group_by”`, will be used as the value.

It is possible to include multiple fields on submit. Instead of passing the ‘name:` and `value:` arguments, pass an array via the `inputs:` argument:

“‘erb <%= render(Primer::Alpha::ActionMenu.new) do |menu| %>

<% menu.with_show_button { "Group By" } %>
<% menu.with_item(
  label: "Repository",
  href: update_repo_grouping_path,
  form_arguments: {
    method: :post,
    inputs: [{
      name: "group_by",
      value: "repository"
    }, {
      name: "some_other_field",
      value: "some value",
    }],
  }
) %>

<% end %> “‘

### Form arguments

The following table summarizes the arguments allowed in the ‘form_arguments:` hash mentioned above.

|Name |Type |Default|Description| |:—————-|:————-|:——|:———-| |‘method` |`Symbol` |`:get` |The HTTP request method to use to submit the form. One of `:get`, `:post`, `:patch`, `:put`, `:delete`, or `:head`| |`name` |`String` |`nil` |The name of the field that will be sent to the server on submit.| |`value` |`String` |`nil` |The value of the field that will be sent to the server on submit.| |`input_arguments`|`Hash` |`{}` |Additional key/value pairs to emit as HTML attributes on the `<input type=“hidden”>` element.| |`inputs` |`Array<Hash>` |`[]` |An array of hashes representing HTML `<input type=“hidden”>` elements. Must contain at least `name:` and `value:` keys. If additional key/value pairs are provided, they are emitted as HTML attributes on the `<input>` element. This argument supercedes the `name:`, `value:`, and `:input_arguments` arguments listed above.|

The elements of the ‘inputs:` array will be emitted as HTML `<input type=“hidden”>` elements.

### JavaScript API

‘ActionMenu`s render an `<action-menu>` custom element that exposes behavior to the client.

#### Query methods

  • ‘getItemById(itemId: string): Element`: Returns the item’s HTML ‘<li>` element. The return value can be passed as the `item` argument to the other methods listed below.

  • ‘isItemChecked(item: Element): boolean`: Returns `true` if the item is checked, `false` otherwise.

  • ‘isItemHidden(item: Element): boolean`: Returns `true` if the item is hidden, `false` otherwise.

  • ‘isItemDisabled(item: Element): boolean`: Returns `true` if the item is disabled, `false` otherwise.

NOTE: Item IDs are special values provided by the user that are attached to ‘ActionMenu` items as the `data-item-id` HTML attribute. Item IDs can be provided by passing an `item_id:` attribute when adding items to the list, eg:

“‘erb <%= render(Primer::Alpha::ActionMenu.new) do |menu| %>

<% menu.with_item(item_id: "my-id") %>

<% end %> “‘

#### State methods

  • ‘showItem(item: Element)`: Shows the item, i.e. makes it visible.

  • ‘hideItem(item: Element)`: Hides the item, i.e. makes it invisible.

  • ‘enableItem(item: Element)`: Enables the item, i.e. makes it clickable by the mouse and keyboard.

  • ‘disableItem(item: Element)`: Disables the item, i.e. makes it unclickable by the mouse and keyboard.

  • ‘checkItem(item: Element)`: Checks the item. Only has an effect in single- and multi-select modes.

  • ‘uncheckItem(item: Element)`: Unchecks the item. Only has an effect in multi-select mode, since items cannot be unchecked in single-select mode.

#### Events

The ‘<action-menu>` element fires an `itemActivated` event whenever an item is activated (eg. clicked) via the mouse or keyboard.

“‘typescript document.querySelector(“action-menu”).addEventListener(“itemActivated”, (event: CustomEvent<ItemActivatedEvent>) =>

event.detail.item     // Element: the <li> item that was activated
event.detail.checked  // boolean: whether or not the result of the activation checked the item

) “‘

Defined Under Namespace

Classes: Group, Heading, List, ListWrapper, Menu, PrimaryMenu, SubMenu, SubMenuItem

Constant Summary

Constants inherited from Component

Component::INVALID_ARIA_LABEL_TAGS

Constants included from Status::Dsl

Status::Dsl::STATUSES

Constants included from ViewHelper

ViewHelper::HELPERS

Constants included from TestSelectorHelper

TestSelectorHelper::TEST_SELECTOR_TAG

Constants included from FetchOrFallbackHelper

FetchOrFallbackHelper::InvalidValueError

Constants included from Primer::AttributesHelper

Primer::AttributesHelper::PLURAL_ARIA_ATTRIBUTES, Primer::AttributesHelper::PLURAL_DATA_ATTRIBUTES

Instance Method Summary collapse

Methods inherited from Component

deprecated?, generate_id

Methods included from JoinStyleArgumentsHelper

#join_style_arguments

Methods included from TestSelectorHelper

#add_test_selector

Methods included from FetchOrFallbackHelper

#fetch_or_fallback, #fetch_or_fallback_boolean, #silence_deprecations?

Methods included from ClassNameHelper

#class_names

Methods included from Primer::AttributesHelper

#aria, #data, #extract_data, #merge_aria, #merge_data, #merge_prefixed_attribute_hashes

Methods included from ExperimentalSlotHelpers

included

Methods included from ExperimentalRenderHelpers

included

Constructor Details

#initialize(**system_arguments) ⇒ ActionMenu

Returns a new instance of ActionMenu.

Parameters:

  • system_arguments (Hash)

    The arguments accepted by <%= link_to_component(Primer::Alpha::ActionMenu::PrimaryMenu) %>.



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'app/components/primer/alpha/action_menu.rb', line 209

def initialize(**system_arguments)
  @primary_menu = PrimaryMenu.allocate
  @system_arguments = @primary_menu.send(:initialize, **system_arguments)

  @system_arguments[:tag] = :"action-menu"
  @system_arguments[:preload] = true if @primary_menu.preload?

  @system_arguments[:data] = merge_data(
    @system_arguments, {
      data: { "select-variant": @primary_menu.select_variant }
    }
  )

  @system_arguments[:"data-dynamic-label"] = "" if @primary_menu.dynamic_label

  if @primary_menu.dynamic_label_prefix.present?
    @system_arguments[:"data-dynamic-label-prefix"] = @primary_menu.dynamic_label_prefix
  end
end

Instance Method Details

#itemsArray<ViewComponent::Slot>

Gets the list of configured menu items, which includes regular items, avatar items, groups, and dividers.

Returns:

  • (Array<ViewComponent::Slot>)


28
29
# File 'app/components/primer/alpha/action_menu.rb', line 28

def items
end

#with_avatar_item(**system_arguments) ⇒ Object

Adds an avatar item to the menu.

Parameters:

  • system_arguments (Hash)

    The arguments accepted by <%= link_to_component(Primer::Alpha::ActionList) %>‘s `item` slot.



10
11
# File 'app/components/primer/alpha/action_menu.rb', line 10

def with_avatar_item(**system_arguments)
end

#with_divider(**system_arguments) ⇒ Object

Adds a divider to the list. Dividers visually separate items.

Parameters:

  • system_arguments (Hash)

    The arguments accepted by <%= link_to_component(Primer::Alpha::ActionList::Divider) %>.



16
17
# File 'app/components/primer/alpha/action_menu.rb', line 16

def with_divider(**system_arguments)
end

#with_group(**system_arguments) ⇒ Object

Adds a group to the menu. Groups are a logical set of items with a header.

Parameters:

  • system_arguments (Hash)

    The arguments accepted by <%= link_to_component(Primer::Alpha::ActionMenu::Group) %>.



22
23
# File 'app/components/primer/alpha/action_menu.rb', line 22

def with_group(**system_arguments)
end

#with_item(**system_arguments) ⇒ Object

Adds an item to the menu.

Parameters:

  • system_arguments (Hash)

    The arguments accepted by <%= link_to_component(Primer::Alpha::ActionList) %>‘s `item` slot.



4
5
# File 'app/components/primer/alpha/action_menu.rb', line 4

def with_item(**system_arguments)
end