-
Notifications
You must be signed in to change notification settings - Fork 486
Closed
Description
Feature request
We could introduce a ViewComponent::Metal class for developers who prefer building components entirely in Ruby, while still keeping the library’s promise of working smoothly with ERB and other template languages. While ViewComponent::Base already supports the call method for simple inline components, there’s room to make it even better. By providing a more friendly syntax, we can avoid the need for repetitive use of concat and capture, making the process more straightforward. If introducing a special class doesn't seem like a good idea, we could instead provide a concern module to add this syntax sugar for pure Ruby components.
Example
class ExampleComponent < ViewComponent::Metal
def template
button(
type: "button",
class: "inline-flex items-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm"
) do
plain "This works"
em do
span "nesting"
strong do
plain "also works"
end
end
end
end
endImplementation
class ViewComponent::Metal
undef :p
def self.tag_elements
@tag_elements ||= ActionView::Helpers::TagHelper::TagBuilder.instance_methods(false)
end
def template
raise NotImplementedError
end
def render_in(view_context)
raise ArgumentError, "#{self.class} does not support passing a block" if block_given?
@view_context = view_context
@view_context.with_output_buffer { template }
end
def plain(string)
@view_context.concat(string)
end
def method_missing(method, ...)
if self.class.tag_elements.include?(method)
@view_context.concat @view_context.tag.__send__(method, ...)
elsif @view_context.respond_to?(method, false)
@view_context.__send__(method, ...)
else
super
end
end
def respond_to_missing?(method, include_all = false)
return true if super
return true if self.class.tag_elements.include?(method)
@view_context.respond_to?(method, false)
end
endMetadata
Metadata
Assignees
Labels
No labels