module ViewComponent::SlotableV2

def set_slot(slot_name, *args, **kwargs, &block)

def set_slot(slot_name, *args, **kwargs, &block)
  slot_definition = self.class.registered_slots[slot_name]
  slot = SlotV2.new(self)
  # Passing the block to the sub-component wrapper like this has two
  # benefits:
  #
  # 1. If this is a `content_area` style sub-component, we will render the
  # block via the `slot`
  #
  # 2. Since we have to pass block content to components when calling
  # `render`, evaluating the block here would require us to call
  # `view_context.capture` twice, which is slower
  slot._content_block = block if block_given?
  # If class
  if slot_definition[:renderable]
    slot._component_instance = slot_definition[:renderable].new(*args, **kwargs)
  # If class name as a string
  elsif slot_definition[:renderable_class_name]
    slot._component_instance = self.class.const_get(slot_definition[:renderable_class_name]).new(*args, **kwargs)
  # If passed a lambda
  elsif slot_definition[:renderable_function]
    # Use `bind(self)` to ensure lambda is executed in the context of the
    # current component. This is necessary to allow the lambda to access helper
    # methods like `content_tag` as well as parent component state.
    renderable_value = slot_definition[:renderable_function].bind(self).call(*args, **kwargs, &block)
    # Function calls can return components, so if it's a component handle it specially
    if renderable_value.respond_to?(:render_in)
      slot._component_instance = renderable_value
    else
      slot._content = renderable_value
    end
  end
  @_set_slots ||= {}
  if slot_definition[:collection]
    @_set_slots[slot_name] ||= []
    @_set_slots[slot_name].push(slot)
  else
    @_set_slots[slot_name] = slot
  end
  nil
end