module ViewComponent::Slotable

def inherited(child)

def inherited(child)
  # Clone slot configuration into child class
  # see #test_slots_pollution
  child.slots = slots.clone
  super
end

def slot(slot_name, **args, &block)


<% end %>
<% end %>

This is my footer!


<% component.slot(:footer, class_names: "footer-class") do %>
<%= render(SlotsComponent.new) do |component| %>
For example:

**args: Arguments to be passed to Slot initializer
slot: Name of Slot, in symbol form

component template.
exposing it for use inside the
Build a Slot instance on a component,
def slot(slot_name, **args, &block)
  # Raise ArgumentError if `slot` doesn't exist
  unless slots.key?(slot_name)
    raise ArgumentError.new "Unknown slot '#{slot_name}' - expected one of '#{slots.keys}'"
  end
  slot = slots[slot_name]
  # The class name of the Slot, such as Header
  slot_class = self.class.const_get(slot[:class_name])
  unless slot_class <= ViewComponent::Slot
    raise ArgumentError.new "#{slot[:class_name]} must inherit from ViewComponent::Slot"
  end
  # Instantiate Slot class, accommodating Slots that don't accept arguments
  slot_instance = args.present? ? slot_class.new(**args) : slot_class.new
  # Capture block and assign to slot_instance#content
  slot_instance.content = view_context.capture(&block).to_s.strip.html_safe if block
  if slot[:collection]
    # Initialize instance variable as an empty array
    # if slot is a collection and has yet to be initialized
    unless instance_variable_defined?(slot[:instance_variable_name])
      instance_variable_set(slot[:instance_variable_name], [])
    end
    # Append Slot instance to collection accessor Array
    instance_variable_get(slot[:instance_variable_name]) << slot_instance
  else
    # Assign the Slot instance to the slot accessor
    instance_variable_set(slot[:instance_variable_name], slot_instance)
  end
  # Return nil, as this method shouldn't output anything to the view itself.
  nil
end

def with_slot(*slot_names, collection: false, class_name: nil)

)
class_name: "Header" # class name string, used to instantiate Slot
collection: true|false,
:header,
with_slot(

support initializing slots as:
def with_slot(*slot_names, collection: false, class_name: nil)
  ViewComponent::Deprecation.warn(
    "`with_slot` is deprecated and will be removed in ViewComponent v3.0.0.\n" \
    "Use the new slots API (https://viewcomponent.org/guide/slots.html) instead."
  )
  slot_names.each do |slot_name|
    # Ensure slot_name isn't already declared
    if slots.key?(slot_name)
      raise ArgumentError.new("#{slot_name} slot declared multiple times")
    end
    # Ensure slot name isn't :content
    if slot_name == :content
      raise ArgumentError.new ":content is a reserved slot name. Please use another name, such as ':body'"
    end
    # Set the name of the method used to access the Slot(s)
    accessor_name =
      if collection
        # If Slot is a collection, set the accessor
        # name to the pluralized form of the slot name
        # For example: :tab => :tabs
        ActiveSupport::Inflector.pluralize(slot_name)
      else
        slot_name
      end
    instance_variable_name = "@#{accessor_name}"
    # If the slot is a collection, define an accesor that defaults to an empty array
    if collection
      class_eval <<-RUBY, __FILE__, __LINE__ + 1
        def #{accessor_name}
          content unless content_evaluated? # ensure content is loaded so slots will be defined
          #{instance_variable_name} ||= []
        end
      RUBY
    else
      class_eval <<-RUBY, __FILE__, __LINE__ + 1
        def #{accessor_name}
          content unless content_evaluated? # ensure content is loaded so slots will be defined
          #{instance_variable_name} if defined?(#{instance_variable_name})
        end
      RUBY
    end
    # Default class_name to ViewComponent::Slot
    class_name = "ViewComponent::Slot" unless class_name.present?
    # Register the slot on the component
    slots[slot_name] = {
      class_name: class_name,
      instance_variable_name: instance_variable_name,
      collection: collection
    }
  end
end