2022-12-15 13:08:20 +01:00
class Dsfr :: InputComponent < ApplicationComponent
2022-12-20 17:51:36 +01:00
delegate :object , to : :@form
delegate :errors , to : :object
# use it to indicate detailed about the inputs, ex: https://www.systeme-de-design.gouv.fr/elements-d-interface/modeles-et-blocs-fonctionnels/demande-de-mot-de-passe
# it uses aria-describedby on input and link it to yielded content
renders_one :describedby
2023-02-15 10:16:01 +01:00
def initialize ( form : , attribute : , input_type : :text_field , opts : { } , required : true )
2022-12-15 13:08:20 +01:00
@form = form
@attribute = attribute
@input_type = input_type
@opts = opts
@required = required
end
2022-12-20 17:51:36 +01:00
# add invalid class on input when input is invalid
# and and valid on input only if another input is invalid
def input_group_opts
opts = {
class : class_names ( 'fr-input-group' : true ,
'fr-password' : password? ,
" fr-input-group--error " : errors_on_attribute? ,
" fr-input-group--valid " : ! errors_on_attribute? && errors_on_another_attribute? )
}
if email?
opts [ :data ] = { controller : 'email-input' }
end
opts
end
def label_opts
{ class : class_names ( 'fr-label' : true , 'fr-password__label' : password? ) }
end
2022-12-15 13:08:20 +01:00
def input_opts
@opts [ :class ] = class_names ( map_array_to_hash_with_true ( @opts [ :class ] )
2022-12-20 17:51:36 +01:00
. merge ( 'fr-password__input' : password? ,
'fr-input' : true ,
2022-12-15 13:08:20 +01:00
'fr-mb-0' : true ,
'fr-input--error' : errors_on_attribute? ) )
2023-02-15 11:33:42 +01:00
if errors_on_attribute? || describedby?
@opts . deep_merge! ( aria : {
describedby : describedby_id ,
invalid : errors_on_attribute?
2022-12-15 13:08:20 +01:00
} )
end
2023-02-15 11:33:42 +01:00
2022-12-15 13:08:20 +01:00
if @required
@opts [ :required ] = true
end
2023-02-15 11:33:42 +01:00
2022-12-20 17:51:36 +01:00
if email?
2023-02-15 11:33:42 +01:00
@opts . deep_merge! ( data : {
2022-12-20 17:51:36 +01:00
action : " blur->email-input # checkEmail " ,
2023-02-15 11:33:42 +01:00
'email-input-target' : 'input'
2022-12-20 17:51:36 +01:00
} )
end
2022-12-15 13:08:20 +01:00
@opts
end
2022-12-20 17:51:36 +01:00
# errors helpers
def errors_on_attribute?
errors . has_key? ( attribute_or_rich_body )
2022-12-15 13:08:20 +01:00
end
2022-12-20 17:51:36 +01:00
def error_messages
errors . full_messages_for ( attribute_or_rich_body )
2022-12-15 13:08:20 +01:00
end
2023-02-15 11:33:42 +01:00
def describedby_id
dom_id ( object , " #{ @attribute } -messages " )
end
2022-12-20 17:51:36 +01:00
# i18n lookups
def label
object . class . human_attribute_name ( @attribute )
2022-12-15 13:08:20 +01:00
end
2022-12-20 17:51:36 +01:00
def hint
I18n . t ( " activerecord.attributes. #{ object . class . name . underscore } .hints. #{ @attribute } " )
2022-12-15 13:08:20 +01:00
end
2022-12-20 17:51:36 +01:00
# kind of input helpers
def password?
@input_type == :password_field
end
def email?
@input_type == :email_field
2022-12-15 13:08:20 +01:00
end
2023-02-07 18:06:38 +01:00
def show_password_id
dom_id ( object , " #{ @attribute } _show_password " )
end
2022-12-15 13:08:20 +01:00
private
2022-12-20 17:51:36 +01:00
def hint?
I18n . exists? ( " activerecord.attributes. #{ object . class . name . underscore } .hints. #{ @attribute } " )
end
2022-12-15 13:08:20 +01:00
def errors_on_another_attribute?
2022-12-20 17:51:36 +01:00
! errors . empty?
2022-12-15 13:08:20 +01:00
end
2022-12-20 17:51:36 +01:00
# lookup for edge case from `form.rich_text_area`
# rich text uses _rich_#{attribute}, but it is saved on #{attribute}, as well as error messages
2022-12-15 13:08:20 +01:00
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