# frozen_string_literal: true require "view_component/version" require "heroicons_helper" module Ariadne # @private class Component < ViewComponent::Base include ViewComponent::SlotableV2 unless ViewComponent::Base < ViewComponent::SlotableV2 include ClassNameHelper include FetchOrFallbackHelper include ViewHelper include Status::Dsl include Audited::Dsl include LoggerHelper include Ariadne::ActionViewExtensions::FormHelper BASE_HTML_CLASSES = "ariadne-h-full ariadne-scroll-smooth ariadne-bg-white ariadne-antialiased" BASE_BODY_CLASSES = "ariadne-flex ariadne-h-full ariadne-flex-col" BASE_WRAPPER_CLASSES = "ariadne-flex ariadne-flex-col ariadne-h-screen ariadne-justify-between" BASE_MAIN_CLASSES = "ariadne-flex-auto" INVALID_ARIA_LABEL_TAGS = [:div, :span, :p].freeze private def raise_on_invalid_options? Rails.application.config.ariadne_view_components.raise_on_invalid_options end private def raise_on_invalid_aria? Rails.application.config.ariadne_view_components.raise_on_invalid_aria end private def deprecated_component_warning(new_class: nil, version: nil) return if silence_deprecations? message = "#{self.class.name} is deprecated" message += " and will be removed in v#{version}." if version message += " Use #{new_class.name} instead." if new_class ActiveSupport::Deprecation.warn(message) end private def aria(val, attributes) attributes[:"aria-#{val}"] || attributes.dig(:aria, val.to_sym) end private def validate_aria_label! aria_label = aria("label", @attributes) raise ArgumentError, "`aria-label` is required." if aria_label.blank? end private def check_denylist(denylist = [], attributes = {}) if should_raise_error? # Convert denylist from: # { [:p, :pt] => "message" } to: # { p: "message", pt: "message" } unpacked_denylist = denylist.each_with_object({}) do |(keys, value), memo| keys.each { |key| memo[key] = value } end violations = unpacked_denylist.keys & attributes.keys if violations.any? message = "Found #{violations.count} #{"violation".pluralize(violations)}:" violations.each do |violation| message += "\n The #{violation} argument is not allowed here. #{unpacked_denylist[violation]}" end raise(ArgumentError, message) end end attributes end private def validate_attributes(tag:, denylist_name: :attributes_denylist, attributes: {}) deny_single_argument(:class, "Use `classes` instead.", attributes) if (denylist = attributes[denylist_name]) check_denylist(denylist, attributes) # Remove :attributes_denylist key and any denied keys from attributes attributes.except!(denylist_name) attributes.except!(*denylist.keys.flatten) end deny_aria_label(tag: tag, attributes: attributes) attributes end private def deny_single_argument(key, help_text, attributes) raise ArgumentError, "`#{key}` is an invalid argument. #{help_text}" \ if should_raise_error? && attributes.key?(key) attributes.except!(key) end private def deny_aria_label(tag:, attributes:) return attributes.except!(:skip_aria_label_check) if attributes[:skip_aria_label_check] return if attributes[:role] return unless INVALID_ARIA_LABEL_TAGS.include?(tag) deny_aria_key( :label, "Don't use `aria-label` on `#{tag}` elements. See https://www.tpgi.com/short-note-on-aria-label-aria-labelledby-and-aria-describedby/", attributes, ) end private def deny_aria_key(key, help_text, attributes) raise ArgumentError, help_text if should_raise_aria_error? && aria(key, attributes) end private def should_raise_error? raise_on_invalid_options? && !ENV["ARIADNE_WARNINGS_DISABLED"] end private def should_raise_aria_error? raise_on_invalid_aria? && !ENV["ARIADNE_WARNINGS_DISABLED"] end end end