76 lines
2 KiB
Ruby
76 lines
2 KiB
Ruby
class Dsfr::InputComponent < ApplicationComponent
|
||
def initialize(form:, attribute:, input_type:, opts: {}, required: true)
|
||
@form = form
|
||
@attribute = attribute
|
||
@input_type = input_type
|
||
@opts = opts
|
||
@required = required
|
||
end
|
||
|
||
def input_opts
|
||
@opts[:class] = class_names(map_array_to_hash_with_true(@opts[:class])
|
||
.merge('fr-input': true,
|
||
'fr-mb-0': true,
|
||
'fr-input--error': errors_on_attribute?))
|
||
|
||
if errors_on_attribute?
|
||
@opts = @opts.deep_merge(aria: {
|
||
describedby: error_message_id,
|
||
invalid: true
|
||
})
|
||
end
|
||
if @required
|
||
@opts[:required] = true
|
||
end
|
||
@opts
|
||
end
|
||
|
||
# add invalid class on input when input is invalid
|
||
# and and valid on input only if another input is invalid
|
||
def input_group_class_names
|
||
class_names('fr-input-group': true,
|
||
"fr-input-group--error": errors_on_attribute?,
|
||
"fr-input-group--valid": !errors_on_attribute? && errors_on_another_attribute?)
|
||
end
|
||
|
||
# tried to inline it within the template, but failed miserably with a double render
|
||
def label
|
||
label = @form.object.class.human_attribute_name(@attribute)
|
||
|
||
if @required
|
||
label += tag.span(" *", class: 'mandatory')
|
||
end
|
||
label
|
||
end
|
||
|
||
def errors_on_attribute?
|
||
@form.object.errors.has_key?(attribute_or_rich_body)
|
||
end
|
||
|
||
def error_message_id
|
||
dom_id(@form.object, @attribute)
|
||
end
|
||
|
||
def error_messages
|
||
@form.object.errors.full_messages_for(attribute_or_rich_body)
|
||
end
|
||
|
||
private
|
||
|
||
def errors_on_another_attribute?
|
||
!@form.object.errors.empty?
|
||
end
|
||
|
||
def attribute_or_rich_body
|
||
case @input_type
|
||
when :rich_text_area
|
||
@attribute.to_s.sub(/\Arich_/, '').to_sym
|
||
else
|
||
@attribute
|
||
end
|
||
end
|
||
|
||
def map_array_to_hash_with_true(array_or_string_or_nil)
|
||
Array(array_or_string_or_nil).to_h { [_1, true] }
|
||
end
|
||
end
|