# frozen_string_literal: true require "heroicons_helper" module Ariadne # `Heroicon` renders an <%= link_to_heroicons %> with <%= link_to_attributes_docs %>. # `Heroicon` can also be rendered with the `heroicon` helper. class HeroiconComponent < Ariadne::Component DEFAULT_TEXT_CLASSES = "ariadne-pl-2" include IconHelper include HeroiconsHelper SIZE_XSMALL = :xs SIZE_SMALL = :sm SIZE_DEFAULT = :md SIZE_LARGE = :lg SIZE_MAPPINGS = { SIZE_XSMALL => 16, SIZE_SMALL => 20, SIZE_DEFAULT => 24, SIZE_LARGE => 128, }.freeze SIZE_OPTIONS = SIZE_MAPPINGS.keys PRELOADED_ICONS = [ { name: "bell", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, }, { name: "check", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, }, { name: "chevron-down", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, }, { name: "clipboard", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, }, { name: "clock", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, }, { name: "information-circle", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, }, { name: "dots-horizontal", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, }, { name: "link", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, }, { name: "lock-closed", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, }, { name: "mail", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, }, { name: "menu", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, }, { name: "pencil", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, }, { name: "plus-sm", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, }, { name: "question-mark-circle", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, }, { name: "search", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, }, { name: "search", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, }, { name: "trash", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, }, { name: "x-mark", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, }, ].freeze # @example Default # <%= render(Ariadne::HeroiconComponent.new(icon: :check, variant: HeroiconsHelper::Icon::VARIANT_OUTLINE)) %> # <%= render(Ariadne::HeroiconComponent.new(icon: :check, variant: HeroiconsHelper::Icon::VARIANT_SOLID)) %> # # @example Medium # <%= render(Ariadne::HeroiconComponent.new(icon: :"user-group", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, size: :md)) %> # # @example Helper # <%= ariadne_heroicon(icon: :check, variant: HeroiconsHelper::Icon::VARIANT_OUTLINE) %> # # @param tag [Symbol, String] The rendered tag name # @param classes [String] <%= link_to_classes_docs %> # @param icon [Symbol, String] Name of <%= link_to_heroicons %> to use. # @param variant [String] <%= one_of(HeroiconsHelper::Icon::VALID_VARIANTS, sort: false) %> # @param size [Symbol] <%= one_of(Ariadne::HeroiconComponent::SIZE_MAPPINGS, sort: false) %> # @param attributes [Hash] <%= link_to_attributes_docs %> # @param text_classes [String] <%= link_to_classes_docs %> # @param text_attributes [Hash] <%= link_to_attributes_docs %> def initialize(tag: :svg, icon:, variant:, size: SIZE_DEFAULT, classes: "", attributes: {}, text_classes: "", text_attributes: {}) @tag = check_incoming_tag(:svg, tag) check_icon_presence!(icon, variant) @attributes = attributes @attributes[:aria] ||= {} if @attributes[:aria][:label] || @attributes[:"aria-label"] @attributes[:role] = "img" else @attributes[:aria][:hidden] = true end # Don't allow sizes under 16px if attributes[:height].present? && attributes[:height].to_i < 16 || attributes[:width].present? && attributes[:width].to_i < 16 attributes.delete(:height) attributes.delete(:width) end # Filter out classify options to prevent them from becoming invalid html attributes. # Note height and width are both classify options and valid html attributes. attributes = { height: @attributes[:height] || SIZE_MAPPINGS[fetch_or_raise(SIZE_OPTIONS, size)], width: @attributes[:width], } @icon = heroicon(icon, variant: variant, **attributes) @classes = class_names( @icon.attributes[:class], classes, ) @attributes.merge!(@icon.attributes.except(:class, :"aria-hidden")) @text_classes = class_names(DEFAULT_TEXT_CLASSES, text_classes) @text_attributes = text_attributes end class << self def _after_compile HeroiconsHelper::Cache.preload!(PRELOADED_ICONS) do |found, icon| HeroiconComponent.new(icon: icon[:name], variant: icon[:variant]) unless found end end end end end