# frozen_string_literal: true module Primer module Alpha class ActionList # An individual `ActionList` item. Items can optionally include leading and/or trailing visuals, # such as icons, avatars, and counters. class Item < Primer::Component DEFAULT_SIZE = :medium SIZE_MAPPINGS = { DEFAULT_SIZE => nil, :large => "ActionListContent--sizeLarge", :xlarge => "ActionListContent--sizeXLarge" }.freeze SIZE_OPTIONS = SIZE_MAPPINGS.keys.freeze DEFAULT_DESCRIPTION_SCHEME = :block DESCRIPTION_SCHEME_MAPPINGS = { :inline => "ActionListItem-descriptionWrap--inline", DEFAULT_DESCRIPTION_SCHEME => "ActionListItem-descriptionWrap" }.freeze DESCRIPTION_SCHEME_OPTIONS = DESCRIPTION_SCHEME_MAPPINGS.keys.freeze DEFAULT_SCHEME = :default SCHEME_MAPPINGS = { DEFAULT_SCHEME => nil, :danger => "ActionListItem--danger" }.freeze SCHEME_OPTIONS = SCHEME_MAPPINGS.keys.freeze DEFAULT_TRUNCATION_BEHAVIOR = :none TRUNCATION_BEHAVIOR_MAPPINGS = { DEFAULT_TRUNCATION_BEHAVIOR => nil, false => nil, :show_tooltip => "ActionListItem-label--truncate", :truncate => "ActionListItem-label--truncate", true => "ActionListItem-label--truncate" } TRUNCATION_BEHAVIOR_OPTIONS = TRUNCATION_BEHAVIOR_MAPPINGS.keys.freeze # Description content that complements the item's label, with optional test_selector. # See `ActionList`'s `description_scheme` argument for layout options. # # @param legacy_content [String] Slot content, provided for backwards-compatibility. Pass a content block instead, or call `with_content`, eg. `component.with_description { "My description" }` or `component.with_description.with_content("My description")`. # @param test_selector [String] The value of this argument is set as the value of a `data-test-selector` HTML attribute on the description element. renders_one :description, -> (legacy_content = nil, test_selector: nil) do Primer::BaseComponent.new(tag: "span", classes: "ActionListItem-description", test_selector: test_selector).tap do |desc| desc.with_content(legacy_content) if legacy_content end end # An icon, avatar, SVG, or custom content that will render to the left of the label. # # To render an icon, call the `with_leading_visual_icon` method, which accepts the arguments accepted by <%= link_to_component(Primer::Beta::Octicon) %>. # # To render an SVG, call the `with_leading_visual_svg` method. # # To render custom content, call the `with_leading_visual_content` method and pass a block that returns a string. renders_one :leading_visual, types: { icon: lambda { |**system_arguments, &block| deny_aria_key( :label, "Avoid using `aria-label` on leading visual icons, as they are purely decorative.", **system_arguments ) Primer::Beta::Octicon.new(**system_arguments, &block) }, avatar: lambda { |*| return unless should_raise_error? raise "Leading visual avatars are no longer supported. Please use the #with_avatar_item slot instead." }, svg: lambda { |**system_arguments| Primer::BaseComponent.new(tag: :svg, width: "16", height: "16", **system_arguments) }, content: lambda { |**system_arguments| Primer::BaseComponent.new(tag: :span, **system_arguments) }, raw_content: nil } # Used internally. # # @private renders_one :private_leading_action_icon, Primer::Beta::Octicon # An icon, label, counter, or text to render to the right of the label. # # To render an icon, call the `with_leading_visual_icon` method, which accepts the arguments accepted by <%= link_to_component(Primer::Beta::Octicon) %>. # # To render a label, call the `with_leading_visual_label` method, which accepts the arguments accepted by <%= link_to_component(Primer::Beta::Label) %>. # # To render a counter, call the `with_leading_visual_counter` method, which accepts the arguments accepted by <%= link_to_component(Primer::Beta::Counter) %>. # # To render text, call the `with_leading_visual_text` method and pass a block that returns a string. Eg: # ```ruby # with_leading_visual_text { "Text here" } # ``` renders_one :trailing_visual, types: { icon: Primer::Beta::Octicon, label: Primer::Beta::Label, counter: Primer::Beta::Counter, text: ->(text) { text } } # Used internally. # # @private renders_one :private_trailing_action_icon, Primer::Beta::Octicon # A button rendered after the trailing icon that can be used to show a menu, activate # a dialog, etc. # # @param system_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Beta::IconButton) %>. renders_one :trailing_action, lambda { |**system_arguments| Primer::Beta::IconButton.new( scheme: :invisible, classes: class_names( system_arguments[:classes], "ActionListItem-trailingAction" ), **system_arguments ) } # `Tooltip` that appears on mouse hover or keyboard focus over the trailing action button. Use tooltips sparingly and as # a last resort. **Important:** This tooltip defaults to `type: :description`. In a few scenarios, `type: :label` may be # more appropriate. Consult the <%= link_to_component(Primer::Alpha::Tooltip) %> documentation for more information. # # @param type [Symbol] (:description) <%= one_of(Primer::Alpha::Tooltip::TYPE_OPTIONS) %> # @param system_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Alpha::Tooltip) %>. renders_one :tooltip, lambda { |**system_arguments| raise ArgumentError, "Buttons with a tooltip must have a unique `id` set on the `Button`." if @id.blank? && !Rails.env.production? system_arguments[:for_id] = @id system_arguments[:type] ||= :description system_arguments[:classes] = class_names(system_arguments[:classes], "ActionListItem-truncationTooltip") if @truncate_label == :show_tooltip Primer::Alpha::Tooltip.new(**system_arguments) } # Used internally. # # @private renders_one :private_content attr_reader :id, :item_id, :list, :href, :active, :disabled, :parent # Whether or not this item is active. # # @return [Boolean] alias active? active # Whether or not this item is disabled. # # @return [Boolean] alias disabled? disabled # @param list [Primer::Alpha::ActionList] The list that contains this item. Used internally. # @param parent [Primer::Alpha::ActionList::Item] This item's parent item. `nil` if this item is at the root. Used internally. # @param label [String] Item label. If no label is provided, content is used. # @param item_id [String] An ID that will be attached to the item's `