Group

bin/rails g quicksilver_ui:form Group

Default

  • With overriden label

  • With hint

  • This is a hint

    With errors

  • Name is invalid

    Implementation

    # frozen_string_literal: true
    
    class Form::Group < UI::Base
      prop :form, AppFormBuilder, reader: :private
      prop :method, _Union(Symbol, String), reader: :private
      prop :type, _Union(:text), reader: :private
      prop :options, Hash, :**, reader: :private
    
      def view_template
        div(class: classes, **data_attributes) do
          render_field
    
          div(class: "space-y-0.5") do
            errors.each do |error|
              render Form::Error.new(form:, method:, text: error, **error_options)
            end
    
            render Form::Hint.new(form:, method:, text: hint_text, **hint_options) if hint?
          end
        end
      end
    
      private
    
      def label_text
        options[:label]
      end
    
      def label_options
        options[:label_options] || {}
      end
    
      def label?
        label_text.present?
      end
    
      def input_options
        options.slice(*input_class.allowed_options)
      end
    
      def error?
        return false if form.object.blank?
    
        form.object.errors.where(method).any?
      end
    
      def errors
        return [] unless error?
    
        form.object.errors.where(method).map(&:full_message)
      end
    
      def error_options
        options[:error_options] || {}
      end
    
      def data_attributes
        return {} unless error?
    
        {data: {invalid: true}}
      end
    
      def hint_text
        options[:hint]
      end
    
      def hint_options
        options[:hint_options] || {}
      end
    
      def hint?
        hint_text.present?
      end
    
      def default_classes
        "space-y-1"
      end
    
      def input_class
        case type
        when :text then Form::TextField
        else
          raise "Type #{type} has no input_class. Add one."
        end
      end
    
      def render_field
        send("render_#{type}")
      end
    
      def render_text
        div(class: "flex flex-col gap-1") do
          render Form::Label.new(form:, method:, text: label_text, **label_options)
          render Form::TextField.new(form:, method:, data:, **input_options)
        end
      end
    end