module ViewComponent::Slotable
def renders_many(slot_name, callable = nil)
<% end %>
two
<% component.with_item(name: "Bar") do %>
<% end %>
One
<% component.with_item(name: "Foo") do %>
<%= render_inline(MyComponent.new) do |component| %>
method can be called multiple times to append to the slot.
helper method with the same name as the slot prefixed with `with_`. The
Consumers of the component can set the content of a slot by calling a
= Setting sub-component content
<% end %>
<%= item %>
<% items.each do |item| %>
helper method with the same name as the slot.
The component's sidecar template can access the slot by calling a
= Rendering sub-components
renders_many :items, ItemComponent
# OR
renders_many :items, -> (name:) { ItemComponent.new(name: name }
= Example
Registers a collection sub-component
#
def renders_many(slot_name, callable = nil) validate_plural_slot_name(slot_name) if callable.is_a?(Hash) && callable.key?(:types) register_polymorphic_slot(slot_name, callable[:types], collection: true) else singular_name = ActiveSupport::Inflector.singularize(slot_name) validate_singular_slot_name(ActiveSupport::Inflector.singularize(slot_name).to_sym) setter_method_name = :"with_#{singular_name}" define_method setter_method_name do |*args, &block| set_slot(slot_name, nil, *args, &block) end ruby2_keywords(setter_method_name) if respond_to?(:ruby2_keywords, true) define_method :"with_#{singular_name}_content" do |content| send(setter_method_name) { content.to_s } self end define_method :"with_#{slot_name}" do |collection_args = nil, &block| collection_args.map do |args| if args.respond_to?(:to_hash) set_slot(slot_name, nil, **args, &block) else set_slot(slot_name, nil, *args, &block) end end end self::GeneratedSlotMethods.define_method slot_name do get_slot(slot_name) end self::GeneratedSlotMethods.define_method :"#{slot_name}?" do get_slot(slot_name).present? end register_slot(slot_name, collection: true, callable: callable) end end