class ViewComponentContrib::Preview::Base

Base view component class with extensions already included

def build_component_instance(locals)

def build_component_instance(locals)
  return locals unless locals[:component].nil?
  locals[:component] = component_class_name.safe_constantize&.new
rescue => e
  locals[:component] = nil
  locals[:error] = e.message
end

def component_class_name

- Button::Preview => Button::Component | ButtonComponent | Button
- Namespace::ButtonPreview => Namespace::Button::Component | Namespace::ButtonComponent | Namespace::Button
Infer component class name from preview class name:
def component_class_name
  @component_class_name ||= begin
    component_name = name.sub(/(::Preview|Preview)$/, "")
    [
      "#{component_name}::Component",
      "#{component_name}Component",
      component_name
    ].find do
      _1.safe_constantize
    end
  end
end

def container_class

def container_class
  return @container_class if defined?(@container_class)
  @container_class =
    if superclass.respond_to?(:container_class)
      superclass.container_class
    else
      DEFAULT_CONTAINER_CLASS
    end
end

def inherited(child)

Support layout inheritance
def inherited(child)
  child.layout(@layout) if defined?(@layout)
  super
end

def render_args(...)

def render_args(...)
  super.tap do |res|
    res[:locals] ||= {}
    build_component_instance(res[:locals])
    res[:locals][:container_class] ||= container_class
  end
end

def render_component(component_or_props = nil, &block)

Shortcut for render_with_template(locals: {component: ...})
def render_component(component_or_props = nil, &block)
  component = if component_or_props.is_a?(::ViewComponent::Base)
    component_or_props
  else
    self.class.component_class_name.constantize.new(**(component_or_props || {}))
  end
  render_with(component: component, content_block: block)
end

def render_with(**locals)

Shortcut for render_with_template(locals: ...)
def render_with(**locals)
  render_with_template(locals: locals)
end