Class: Pulse::ActionList

Inherits:
Component
  • Object
show all
Defined in:
app/components/pulse/action_list.rb,
app/components/pulse/action_list/item.rb,
app/components/pulse/action_list/divider.rb,
app/components/pulse/action_list/heading.rb,
app/components/pulse/action_list/form_wrapper.rb

Overview

An ActionList is a styled list of links. It acts as the base component for many other menu-type components, including ActionMenu and SelectPanel, as well as the navigational component NavList.

Each item in an action list can be augmented by specifying corresponding leading and/or trailing visuals.

Direct Known Subclasses

NavList::Group

Defined Under Namespace

Classes: Divider, FormWrapper, Heading, Item

Constant Summary collapse

DEFAULT_ROLE =
:list
:menu
DEFAULT_MENU_ITEM_ROLE =
:menuitem
DEFAULT_SCHEME =
:full
SCHEME_MAPPINGS =
{
  DEFAULT_SCHEME => nil,
  :inset => 'ActionListWrap--inset'
}.freeze
SCHEME_OPTIONS =
SCHEME_MAPPINGS.keys.freeze
DEFAULT_SELECT_VARIANT =
:none
SELECT_VARIANT_OPTIONS =
[
  :single,
  :multiple,
  :multiple_checkbox,
  DEFAULT_SELECT_VARIANT
].freeze
SELECT_VARIANT_ROLE_MAP =
{
  single: :menuitemradio,
  multiple: :menuitemcheckbox,
  multiple_checkbox: :menuitemcheckbox
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(id: self.class.generate_id, role: nil, item_classes: nil, scheme: DEFAULT_SCHEME, show_dividers: false, select_variant: DEFAULT_SELECT_VARIANT, form_arguments: {}, **system_arguments) ⇒ ActionList

Returns a new instance of ActionList.

Parameters:

  • id (String) (defaults to: self.class.generate_id)

    HTML ID value.

  • role (Boolean) (defaults to: nil)

    ARIA role describing the function of the list. listbox and menu are a common values.

  • item_classes (String) (defaults to: nil)

    Additional CSS classes to attach to items.

  • scheme (Symbol) (defaults to: DEFAULT_SCHEME)

    <%= one_of(Pulse::ActionList::SCHEME_OPTIONS) %> inset children are offset (vertically and horizontally) from list edges. full (default) children are flush (vertically and horizontally) with list edges.

  • show_dividers (Boolean) (defaults to: false)

    Display a divider above each item in the list when it does not follow a header or divider.

  • select_variant (Symbol) (defaults to: DEFAULT_SELECT_VARIANT)

    How items may be selected in the list. <%= one_of(Pulse::ActionList::SELECT_VARIANT_OPTIONS) %>

  • form_arguments (Hash) (defaults to: {})

    Allows an ActionList to act as a select list in multi- and single-select modes. Pass the builder: and name: options to this hash. builder: should be an instance of ActionView::Helpers::FormBuilder, which are created by the standard Rails #form_with and #form_for helpers. The name: option is the desired name of the field that will be included in the params sent to the server on form submission. NOTE: Consider using an <%= link_to_component(Pulse::ActionMenu) %> instead of using this feature directly.

  • system_arguments (Hash)

    <%= link_to_system_arguments_docs %>

Raises:

  • (ArgumentError)


121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'app/components/pulse/action_list.rb', line 121

def initialize(
  id: self.class.generate_id,
  role: nil,
  item_classes: nil,
  scheme: DEFAULT_SCHEME,
  show_dividers: false,
  select_variant: DEFAULT_SELECT_VARIANT,
  form_arguments: {},
  **system_arguments
)
  @system_arguments = system_arguments
  @id = id
  @system_arguments[:id] = @id
  @system_arguments[:tag] = :ul
  @item_classes = item_classes
  @scheme = fetch_or_fallback(SCHEME_OPTIONS, scheme, DEFAULT_SCHEME)
  @show_dividers = show_dividers
  @select_variant = select_variant
  @system_arguments[:classes] = merge_classes(
    SCHEME_MAPPINGS[@scheme],
    system_arguments[:classes],
    'ActionListWrap--divided' => @show_dividers
  )

  @role = role || (allows_selection? ? MENU_ROLE : DEFAULT_ROLE)
  @system_arguments[:role] = @role

  @list_wrapper_arguments = {}

  @form_builder = form_arguments[:builder]
  @input_name = form_arguments[:name]

  return unless required_form_arguments_given? && !allows_selection?

  raise ArgumentError,
        'lists/menus that act as form inputs must also allow item ' \
        'selection (please pass the `select_variant:` option)'
end

Instance Attribute Details

#idObject (readonly)

Returns the value of attribute id.



111
112
113
# File 'app/components/pulse/action_list.rb', line 111

def id
  @id
end

#roleObject (readonly)

Returns the value of attribute role.



111
112
113
# File 'app/components/pulse/action_list.rb', line 111

def role
  @role
end

#select_variantObject (readonly)

Returns the value of attribute select_variant.



111
112
113
# File 'app/components/pulse/action_list.rb', line 111

def select_variant
  @select_variant
end

Class Method Details

.custom_element_nameObject

simplecov:disable



39
40
41
# File 'app/components/pulse/action_list.rb', line 39

def self.custom_element_name
  @custom_element_name ||= name.split('::').last.underscore.dasherize
end

Instance Method Details

#acts_as_form_input?Boolean

Returns:

  • (Boolean)


246
247
248
# File 'app/components/pulse/action_list.rb', line 246

def acts_as_form_input?
  required_form_arguments_given? && allows_selection?
end

#acts_as_menu?Boolean

Returns:

  • (Boolean)


238
239
240
# File 'app/components/pulse/action_list.rb', line 238

def acts_as_menu?
  @system_arguments[:role] == :menu
end

#allows_selection?Boolean

Returns:

  • (Boolean)


234
235
236
# File 'app/components/pulse/action_list.rb', line 234

def allows_selection?
  single_select? || multi_select?
end

#before_renderObject



161
162
163
164
165
166
167
168
169
# File 'app/components/pulse/action_list.rb', line 161

def before_render
  return unless heading?

  @system_arguments[:'aria-labelledby'] = heading.title_id
  return unless heading.subtitle?

  @system_arguments[:'aria-describedby'] =
    heading.subtitle_id
end

#build_avatar_item(src:, username:, full_name: nil, full_name_scheme: Pulse::ActionList::Item::DEFAULT_DESCRIPTION_SCHEME, component_klass: ActionList::Item, avatar_arguments: {}, **system_arguments) ⇒ Object

Builds a new avatar item but does not add it to the list. Avatar items are a convenient way to accessibly add an item with a leading avatar image. Use this method instead of the #with_avatar_item slot if you need to render an avatar item outside the context of a list, eg. if rendering additional items to append to an existing list, perhaps via a separate HTTP request.

Parameters:

  • src (String)

    The source url of the avatar image.

  • username (String)

    The username associated with the avatar.

  • full_name (String) (defaults to: nil)

    Optional. The user's full name.

  • full_name_scheme (Symbol) (defaults to: Pulse::ActionList::Item::DEFAULT_DESCRIPTION_SCHEME)

    Optional. How to display the user's full name. <%= one_of(Pulse::ActionList::Item::DESCRIPTION_SCHEME_OPTIONS) %>

  • component_klass (Class) (defaults to: ActionList::Item)

    The class to use instead of the default <%= link_to_component(Pulse::ActionList::Item) %>

  • avatar_arguments (Hash) (defaults to: {})

    Optional. The arguments accepted by <%= link_to_component(Pulse::Avatar) %>

  • system_arguments (Hash)

    These arguments are forwarded to <%= link_to_component(Pulse::ActionList::Item) %>, or whatever class is passed as the component_klass argument.



208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'app/components/pulse/action_list.rb', line 208

def build_avatar_item(
  src:, username:, full_name: nil,
  full_name_scheme: Pulse::ActionList::Item::DEFAULT_DESCRIPTION_SCHEME,
  component_klass: ActionList::Item, avatar_arguments: {},
  **system_arguments
)
  build_item(label: username, description_scheme: full_name_scheme,
             component_klass:, **system_arguments).tap do |item|
    item.with_leading_visual_raw_content do
      # no alt text necessary for presentational item
      item.render(Pulse::Avatar.new(src:, **avatar_arguments,
                                    role: :presentation, size: 16))
    end

    item.with_description_content(full_name) if full_name
  end
end

#build_item(component_klass: ActionList::Item, **system_arguments) ⇒ Object

Builds a new item but does not add it to the list. Use this method instead of the #with_item slot if you need to render an item outside the context of a list, eg. if rendering additional items to append to an existing list, perhaps via a separate HTTP request.

Parameters:

  • component_klass (Class) (defaults to: ActionList::Item)

    The class to use instead of the default <%= link_to_component(Pulse::ActionList::Item) %>

  • system_arguments (Hash)

    These arguments are forwarded to <%= link_to_component(Pulse::ActionList::Item) %>, or whatever class is passed as the component_klass argument.



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'app/components/pulse/action_list.rb', line 178

def build_item(component_klass: ActionList::Item, **system_arguments)
  if single_select? &&
     system_arguments[:active] &&
     items.any?(&:active?)
    raise ArgumentError,
          'only a single item may be active when select_variant is ' \
          'set to :single'
  end
  system_arguments[:classes] = merge_classes(
    @item_classes,
    system_arguments[:classes]
  )

  component_klass.new(list: self, **system_arguments)
end

#multi_select?Boolean

Returns:

  • (Boolean)


230
231
232
# File 'app/components/pulse/action_list.rb', line 230

def multi_select?
  [:multiple, :multiple_checkbox].include?(select_variant)
end

#required_form_arguments_given?Boolean

Returns:

  • (Boolean)


242
243
244
# File 'app/components/pulse/action_list.rb', line 242

def required_form_arguments_given?
  @form_builder && @input_name
end

#single_select?Boolean

Returns:

  • (Boolean)


226
227
228
# File 'app/components/pulse/action_list.rb', line 226

def single_select?
  select_variant == :single
end

#will_add_item(_item) ⇒ Object



251
# File 'app/components/pulse/action_list.rb', line 251

def will_add_item(_item); end

#with_avatar_item(src:, username:, full_name: nil, full_name_scheme: Pulse::ActionList::Item::DEFAULT_DESCRIPTION_SCHEME, component_klass: ActionList::Item, avatar_arguments: {}, **system_arguments, &block) ⇒ Object

Adds an avatar item to the list. Avatar items are a convenient way to accessibly add an item with a leading avatar image.

Parameters:

  • src (String)

    The source url of the avatar image.

  • username (String)

    The username associated with the avatar.

  • full_name (String) (defaults to: nil)

    Optional. The user's full name.

  • full_name_scheme (Symbol) (defaults to: Pulse::ActionList::Item::DEFAULT_DESCRIPTION_SCHEME)

    Optional. How to display the user's full name. <%= one_of(Pulse::ActionList::Item::DESCRIPTION_SCHEME_OPTIONS) %>

  • component_klass (Class) (defaults to: ActionList::Item)

    The class to use instead of the default <%= link_to_component(Pulse::ActionList::Item) %>

  • avatar_arguments (Hash) (defaults to: {})

    Optional. The arguments accepted by <%= link_to_component(Pulse::Avatar) %>

  • system_arguments (Hash)

    These arguments are forwarded to <%= link_to_component(Pulse::ActionList::Item) %>, or whatever class is passed as the component_klass argument.



# File 'app/components/pulse/action_list.rb', line 69

#with_divider(**system_arguments, &block) ⇒ Object

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

Parameters:

  • system_arguments (Hash)

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



# File 'app/components/pulse/action_list.rb', line 62

#with_item(**system_arguments, &block) ⇒ Object

Adds an item to the list.

Parameters:

  • component_klass (Class)

    The class to use instead of the default <%= link_to_component(Pulse::ActionList::Item) %>

  • system_arguments (Hash)

    These arguments are forwarded to <%= link_to_component(Pulse::ActionList::Item) %>, or whatever class is passed as the component_klass argument.



# File 'app/components/pulse/action_list.rb', line 54