From d27e4fc69319c454304eefd4ad6031731f0445a0 Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 11 Dec 2023 17:30:06 +0100 Subject: [PATCH 1/4] =?UTF-8?q?amelioration(combobox):=20permet=20de=20pas?= =?UTF-8?q?ser=20des=20options=20au=20input[type=3Dhidden],=20utilise=20ce?= =?UTF-8?q?tte=20option=20pour=20autosubmit=20uniquement=20un=20input=20[d?= =?UTF-8?q?ans=20notre=20cas,=20ne=20soumet=20pas=20a=20l'input=20du=20com?= =?UTF-8?q?bobox,=20mais=20a=20l'input=20hidden=20une=20fois=20le=20combob?= =?UTF-8?q?ox=20selectionn=C3=A9]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../instructeur_filter_component.html.haml | 6 +++++- app/components/dsfr/combobox_component.rb | 19 +++++++++++-------- .../combobox_component.html.haml | 4 ++-- .../controllers/autosubmit_controller.ts | 7 ++++++- .../dsfr/combobox_component_preview.rb | 4 ++-- 5 files changed, 26 insertions(+), 14 deletions(-) diff --git a/app/components/dossiers/instructeur_filter_component/instructeur_filter_component.html.haml b/app/components/dossiers/instructeur_filter_component/instructeur_filter_component.html.haml index d3234e08a..8afad1b45 100644 --- a/app/components/dossiers/instructeur_filter_component/instructeur_filter_component.html.haml +++ b/app/components/dossiers/instructeur_filter_component/instructeur_filter_component.html.haml @@ -1,7 +1,11 @@ = form_tag add_filter_instructeur_procedure_path(procedure), method: :post, class: 'dropdown-form large', id: 'filter-component', data: { turbo: true, controller: 'autosubmit' } do .fr-select-group = label_tag :field, t('.column'), class: 'fr-label fr-m-0', id: 'instructeur-filter-combo-label', for: 'search-filter' - = render Dsfr::ComboboxComponent.new form: nil, name: :field, options: filterable_fields_for_select, selected: field_id, id: 'search-filter', class: 'fr-select', describedby: 'instructeur-filter-combo-label', allows_custom_value: false, allows_blank: false, form_id: 'filter-component', data: { no_autosubmit: ['input', 'blur'].join(' '), no_autosubmit_on_empty: "true" } + = render Dsfr::ComboboxComponent.new form: nil, + options: filterable_fields_for_select, + selected: field_id, + input_html_options: { name: :field, id: 'search-filter', class: 'fr-select', describedby: 'instructeur-filter-combo-label', allows_custom_value: false, form_id: 'filter-component' }, + hidden_html_options: { data: { no_autosubmit: ['input', 'blur'].join(' '), no_autosubmit_on_empty: "true", autosubmit_target: 'input' } } %input.hidden{ type: 'submit', formaction: update_filter_instructeur_procedure_path(procedure), data: { autosubmit_target: 'submitter' } } diff --git a/app/components/dsfr/combobox_component.rb b/app/components/dsfr/combobox_component.rb index 760bab581..a503cba8b 100644 --- a/app/components/dsfr/combobox_component.rb +++ b/app/components/dsfr/combobox_component.rb @@ -1,6 +1,6 @@ class Dsfr::ComboboxComponent < ApplicationComponent - def initialize(form: nil, options: nil, url: nil, selected: nil, allows_custom_value: false, **html_options) - @form, @options, @url, @selected, @allows_custom_value, @html_options = form, options, url, selected, allows_custom_value, html_options + def initialize(form: nil, options: nil, url: nil, selected: nil, allows_custom_value: false, input_html_options: {}, hidden_html_options: {}) + @form, @options, @url, @selected, @allows_custom_value, @input_html_options, @hidden_html_options = form, options, url, selected, allows_custom_value, input_html_options, hidden_html_options end attr_reader :form, :options, :url, :selected, :allows_custom_value @@ -8,11 +8,11 @@ class Dsfr::ComboboxComponent < ApplicationComponent private def name - @html_options[:name] + @input_html_options[:name] end def form_id - @html_options[:form_id] + @input_html_options[:form_id] end def html_input_options @@ -23,18 +23,21 @@ class Dsfr::ComboboxComponent < ApplicationComponent id: input_id, class: input_class, role: 'combobox', - data: @html_options[:data], 'aria-expanded': 'false', - 'aria-describedby': @html_options[:describedby] + 'aria-describedby': @input_html_options[:describedby] }.compact end + def hidden_html_options + @hidden_html_options || {} + end + def input_id - @html_options[:id] + @input_html_options[:id] end def input_class - "#{@html_options[:class].presence || ''} fr-select" + "#{@input_html_options[:class].presence || ''} fr-select" end def selected_option_label_input_value diff --git a/app/components/dsfr/combobox_component/combobox_component.html.haml b/app/components/dsfr/combobox_component/combobox_component.html.haml index 4bf6c44fc..a0440db91 100644 --- a/app/components/dsfr/combobox_component/combobox_component.html.haml +++ b/app/components/dsfr/combobox_component/combobox_component.html.haml @@ -2,9 +2,9 @@ .fr-ds-combobox-input %input{ value: selected_option_label_input_value, **html_input_options } - if form - = form.hidden_field name, value: selected_option_value_input_value, form: form_id, data: html_input_options[:data] + = form.hidden_field name, value: selected_option_value_input_value, form: form_id, **hidden_html_options - else - %input{ type: 'hidden', name: name, value: selected_option_value_input_value, form: form_id, data: html_input_options[:data] } + %input{ type: 'hidden', name: name, value: selected_option_value_input_value, form: form_id, **hidden_html_options } .fr-menu %ul.fr-menu__list.hidden{ role: 'listbox', hidden: true, id: list_id, data: { turbo_force: :browser, options: options_json, url:, hints: hints_json }.compact } .sr-only{ aria: { live: 'polite', atomic: 'true' }, data: { turbo_force: :browser } } diff --git a/app/javascript/controllers/autosubmit_controller.ts b/app/javascript/controllers/autosubmit_controller.ts index a5f29cbb4..fd037864b 100644 --- a/app/javascript/controllers/autosubmit_controller.ts +++ b/app/javascript/controllers/autosubmit_controller.ts @@ -7,10 +7,11 @@ const AUTOSUBMIT_DATE_DEBOUNCE_DELAY = 5000; const AUTOSUBMIT_EVENTS = ['input', 'change', 'blur']; export class AutosubmitController extends ApplicationController { - static targets = ['submitter']; + static targets = ['submitter', 'input']; declare readonly submitterTarget: HTMLButtonElement | HTMLInputElement; declare readonly hasSubmitterTarget: boolean; + declare readonly inputTarget: HTMLInputElement; #dateTimeChangedInputs = new WeakSet(); @@ -66,6 +67,7 @@ export class AutosubmitController extends ApplicationController { private findTargetElement(event: Event) { const target = event.target; + if ( !isFormInputElement(target) || this.preventAutosubmit(target, event.type) @@ -82,6 +84,9 @@ export class AutosubmitController extends ApplicationController { if (target.disabled) { return true; } + if (this.hasInputTarget && this.inputTarget != target) { + return true; + } if ( Boolean(target.getAttribute('data-no-autosubmit-on-empty')) && target.value == '' diff --git a/spec/components/previews/dsfr/combobox_component_preview.rb b/spec/components/previews/dsfr/combobox_component_preview.rb index 29ea63c3f..57367fd28 100644 --- a/spec/components/previews/dsfr/combobox_component_preview.rb +++ b/spec/components/previews/dsfr/combobox_component_preview.rb @@ -103,10 +103,10 @@ class Dsfr::ComboboxComponentPreview < ViewComponent::Preview ] def simple_select_with_options - render Dsfr::ComboboxComponent.new(name: :value, options: OPTIONS, selected: OPTIONS.sample, id: 'simple-select', class: 'width-33') + render Dsfr::ComboboxComponent.new(options: OPTIONS, selected: OPTIONS.sample, input_html_options: { name: :value, id: 'simple-select', class: 'width-33' }) end def simple_select_with_options_and_allows_custom_value - render Dsfr::ComboboxComponent.new(name: :value, options: OPTIONS, selected: OPTIONS.sample, id: 'simple-select', class: 'width-33', allows_custom_value: true) + render Dsfr::ComboboxComponent.new(options: OPTIONS, selected: OPTIONS.sample, allows_custom_value: true, input_html_options: { id: 'simple-select', class: 'width-33', name: :value }) end end From 95fd6c2a69c9aba55ddeba8ee175d715409da5a2 Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 11 Dec 2023 17:30:37 +0100 Subject: [PATCH 2/4] tech(combobox): propage le changement de signature dans le reste de la codebase --- .../address_component/address_component.html.haml | 2 +- .../communes_component/communes_component.html.haml | 2 +- .../drop_down_list_component.html.haml | 2 +- .../chorus_form_component/chorus_form_component.html.haml | 5 +---- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/app/components/editable_champ/address_component/address_component.html.haml b/app/components/editable_champ/address_component/address_component.html.haml index a065d0432..e69322a16 100644 --- a/app/components/editable_champ/address_component/address_component.html.haml +++ b/app/components/editable_champ/address_component/address_component.html.haml @@ -1,2 +1,2 @@ -= render Dsfr::ComboboxComponent.new form: @form, name: :value, url: data_sources_data_source_adresse_path, selected: @champ.value, id: @champ.input_id, class: 'fr-select', describedby: @champ.describedby_id, allows_custom_value: true do += render Dsfr::ComboboxComponent.new form: @form, url: data_sources_data_source_adresse_path, selected: @champ.value, allows_custom_value: true, input_html_options: { name: :value, id: @champ.input_id, class: 'fr-select', describedby: @champ.describedby_id } do = @form.hidden_field :external_id, data: { value_slot: 'value' } diff --git a/app/components/editable_champ/communes_component/communes_component.html.haml b/app/components/editable_champ/communes_component/communes_component.html.haml index 00bb15c6b..e1af572e8 100644 --- a/app/components/editable_champ/communes_component/communes_component.html.haml +++ b/app/components/editable_champ/communes_component/communes_component.html.haml @@ -1,2 +1,2 @@ -= render Dsfr::ComboboxComponent.new form: @form, name: :external_id, url: data_sources_data_source_commune_path, selected: [@champ.to_s, @champ.selected], id: @champ.input_id, class: 'fr-select', describedby: @champ.describedby_id do += render Dsfr::ComboboxComponent.new form: @form, url: data_sources_data_source_commune_path, selected: [@champ.to_s, @champ.selected], input_html_options: { name: :external_id, id: @champ.input_id, class: 'fr-select', describedby: @champ.describedby_id } do = @form.hidden_field :code_postal, data: { value_slot: 'data:string' } diff --git a/app/components/editable_champ/drop_down_list_component/drop_down_list_component.html.haml b/app/components/editable_champ/drop_down_list_component/drop_down_list_component.html.haml index 18412fddb..0722af4f3 100644 --- a/app/components/editable_champ/drop_down_list_component/drop_down_list_component.html.haml +++ b/app/components/editable_champ/drop_down_list_component/drop_down_list_component.html.haml @@ -18,7 +18,7 @@ %label.fr-label{ for: "#{@champ.id}_radio_option_other" } = t('shared.champs.drop_down_list.other') - elsif @champ.render_as_combobox? - = render Dsfr::ComboboxComponent.new form: @form, name: :value, options: @champ.enabled_non_empty_options(other: true), selected: @champ.selected, id: @champ.input_id, class: select_class_names, describedby: @champ.describedby_id + = render Dsfr::ComboboxComponent.new form: @form, options: @champ.enabled_non_empty_options(other: true), selected: @champ.selected, input_html_options: { name: :value, id: @champ.input_id, class: select_class_names, describedby: @champ.describedby_id } - else = @form.select :value, @champ.enabled_non_empty_options(other: true), diff --git a/app/components/procedure/chorus_form_component/chorus_form_component.html.haml b/app/components/procedure/chorus_form_component/chorus_form_component.html.haml index 009eacf5a..3fe78a9d3 100644 --- a/app/components/procedure/chorus_form_component/chorus_form_component.html.haml +++ b/app/components/procedure/chorus_form_component/chorus_form_component.html.haml @@ -6,10 +6,7 @@ = render Dsfr::ComboboxComponent.new form: f, url: datasource_endpoint, selected: format_displayed_value(chorus_configuration_attribute), - id: chorus_configuration_attribute, - class: 'fr-select', - describedby: label_id, - name: :chorus_configuration_attribute do + input_html_options: { id: chorus_configuration_attribute, class: 'fr-select', describedby: label_id, name: :chorus_configuration_attribute } do = f.hidden_field chorus_configuration_attribute, data: { value_slot: 'data' }, value: format_hidden_value(chorus_configuration_attribute) = f.submit "Enregister", class: 'fr-btn' From 0caacdaf59392089e49f8aeeb88ecc91c3571284 Mon Sep 17 00:00:00 2001 From: Martin Date: Tue, 12 Dec 2023 09:49:38 +0100 Subject: [PATCH 3/4] amelioration(combobox): utilise une loupe plutot qu'un chevron bas pour les combobox en mode autocomplete --- .scss-lint.yml | 1 + app/assets/stylesheets/dsfr.scss | 7 +++++++ app/components/dsfr/combobox_component.rb | 6 +++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.scss-lint.yml b/.scss-lint.yml index d615d0ea1..b67166b4b 100644 --- a/.scss-lint.yml +++ b/.scss-lint.yml @@ -1,6 +1,7 @@ exclude: - 'app/assets/stylesheets/reset.scss' - 'app/assets/stylesheets/direct_uploads.scss' + - 'app/assets/stylesheets/dsfr.scss' linters: BangFormat: diff --git a/app/assets/stylesheets/dsfr.scss b/app/assets/stylesheets/dsfr.scss index 356eecfde..36e0eb03b 100644 --- a/app/assets/stylesheets/dsfr.scss +++ b/app/assets/stylesheets/dsfr.scss @@ -33,6 +33,13 @@ trix-editor.fr-input { width: 100%; } } + .fr-autocomplete{ + // override dsfr chevron down which is + // --data-uri-svg: url("data:image/svg+xml;charset=utf-8,"); + // use a magnifier instead + --data-uri-svg: url("data:image/svg+xml;charset=utf-8,"); + background-image: var(--data-uri-svg); + } } @media (max-width: 62em) { diff --git a/app/components/dsfr/combobox_component.rb b/app/components/dsfr/combobox_component.rb index a503cba8b..8a345cee5 100644 --- a/app/components/dsfr/combobox_component.rb +++ b/app/components/dsfr/combobox_component.rb @@ -37,7 +37,11 @@ class Dsfr::ComboboxComponent < ApplicationComponent end def input_class - "#{@input_html_options[:class].presence || ''} fr-select" + class_names( + "#{@input_html_options[:class]}": @input_html_options[:class].presence, + 'fr-select': true, + 'fr-autocomplete': @url.presence + ) end def selected_option_label_input_value From b539fe1b65661f48cb3a8e2dde4eea590ed0cfd7 Mon Sep 17 00:00:00 2001 From: mfo Date: Wed, 13 Dec 2023 16:14:37 +0100 Subject: [PATCH 4/4] amelioration(review): tech review Co-authored-by: Colin Darie --- .scss-lint.yml | 2 +- app/assets/stylesheets/dsfr.scss | 9 +++------ app/components/dsfr/combobox_component.rb | 4 ---- .../dsfr/combobox_component/combobox_component.html.haml | 4 ++-- app/javascript/controllers/autosubmit_controller.ts | 1 + 5 files changed, 7 insertions(+), 13 deletions(-) diff --git a/.scss-lint.yml b/.scss-lint.yml index b67166b4b..dd6d398cf 100644 --- a/.scss-lint.yml +++ b/.scss-lint.yml @@ -1,7 +1,7 @@ exclude: - 'app/assets/stylesheets/reset.scss' - 'app/assets/stylesheets/direct_uploads.scss' - - 'app/assets/stylesheets/dsfr.scss' + - 'app/assets/stylesheets/dsfr_override.scss' linters: BangFormat: diff --git a/app/assets/stylesheets/dsfr.scss b/app/assets/stylesheets/dsfr.scss index 36e0eb03b..ab27cfff0 100644 --- a/app/assets/stylesheets/dsfr.scss +++ b/app/assets/stylesheets/dsfr.scss @@ -33,12 +33,9 @@ trix-editor.fr-input { width: 100%; } } - .fr-autocomplete{ - // override dsfr chevron down which is - // --data-uri-svg: url("data:image/svg+xml;charset=utf-8,"); - // use a magnifier instead - --data-uri-svg: url("data:image/svg+xml;charset=utf-8,"); - background-image: var(--data-uri-svg); + + .fr-autocomplete { + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M18.031 16.6168L22.3137 20.8995L20.8995 22.3137L16.6168 18.031C15.0769 19.263 13.124 20 11 20C6.032 20 2 15.968 2 11C2 6.032 6.032 2 11 2C15.968 2 20 6.032 20 11C20 13.124 19.263 15.0769 18.031 16.6168ZM16.0247 15.8748C17.2475 14.6146 18 12.8956 18 11C18 7.1325 14.8675 4 11 4C7.1325 4 4 7.1325 4 11C4 14.8675 7.1325 18 11 18C12.8956 18 14.6146 17.2475 15.8748 16.0247L16.0247 15.8748Z'%3E%3C/path%3E%3C/svg%3E"); } } diff --git a/app/components/dsfr/combobox_component.rb b/app/components/dsfr/combobox_component.rb index 8a345cee5..d720875f1 100644 --- a/app/components/dsfr/combobox_component.rb +++ b/app/components/dsfr/combobox_component.rb @@ -28,10 +28,6 @@ class Dsfr::ComboboxComponent < ApplicationComponent }.compact end - def hidden_html_options - @hidden_html_options || {} - end - def input_id @input_html_options[:id] end diff --git a/app/components/dsfr/combobox_component/combobox_component.html.haml b/app/components/dsfr/combobox_component/combobox_component.html.haml index a0440db91..86dfdc7ce 100644 --- a/app/components/dsfr/combobox_component/combobox_component.html.haml +++ b/app/components/dsfr/combobox_component/combobox_component.html.haml @@ -2,9 +2,9 @@ .fr-ds-combobox-input %input{ value: selected_option_label_input_value, **html_input_options } - if form - = form.hidden_field name, value: selected_option_value_input_value, form: form_id, **hidden_html_options + = form.hidden_field name, value: selected_option_value_input_value, form: form_id, **@hidden_html_options - else - %input{ type: 'hidden', name: name, value: selected_option_value_input_value, form: form_id, **hidden_html_options } + %input{ type: 'hidden', name: name, value: selected_option_value_input_value, form: form_id, **@hidden_html_options } .fr-menu %ul.fr-menu__list.hidden{ role: 'listbox', hidden: true, id: list_id, data: { turbo_force: :browser, options: options_json, url:, hints: hints_json }.compact } .sr-only{ aria: { live: 'polite', atomic: 'true' }, data: { turbo_force: :browser } } diff --git a/app/javascript/controllers/autosubmit_controller.ts b/app/javascript/controllers/autosubmit_controller.ts index fd037864b..156d54afa 100644 --- a/app/javascript/controllers/autosubmit_controller.ts +++ b/app/javascript/controllers/autosubmit_controller.ts @@ -12,6 +12,7 @@ export class AutosubmitController extends ApplicationController { declare readonly submitterTarget: HTMLButtonElement | HTMLInputElement; declare readonly hasSubmitterTarget: boolean; declare readonly inputTarget: HTMLInputElement; + declare readonly hasInputTarget: boolean; #dateTimeChangedInputs = new WeakSet();