chore(form): respect dsfr fr-fieldset and elements expected markup
This commit is contained in:
parent
2cec44109d
commit
60882e0844
4 changed files with 88 additions and 36 deletions
|
@ -27,7 +27,7 @@
|
|||
|
||||
.section-2 {
|
||||
margin-top: 1.5rem;
|
||||
padding-top: 1rem;
|
||||
padding-top: 2rem;
|
||||
border-top: 2px solid var(--border-default-grey);
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,11 @@
|
|||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
// Keep only bottom margin in nested (consecutive) header sections, ie. first legend for a same level
|
||||
.fr-fieldset > .fr-fieldset__legend + .fr-fieldset__element > .fr-fieldset:first-of-type .header-section {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
legend {
|
||||
width: 100%;
|
||||
}
|
||||
|
|
|
@ -8,11 +8,11 @@ class EditableChamp::SectionComponent < ApplicationComponent
|
|||
end
|
||||
|
||||
def render_within_fieldset?
|
||||
first_champ_is_an_header_section? && any_champ_fillable?
|
||||
first_champ_is_an_header_section?
|
||||
end
|
||||
|
||||
def header_section
|
||||
return @nodes.first if @nodes.first.is_a?(Champs::HeaderSectionChamp)
|
||||
@nodes.first if @nodes.first.is_a?(Champs::HeaderSectionChamp)
|
||||
end
|
||||
|
||||
def splitted_tail
|
||||
|
@ -30,13 +30,6 @@ class EditableChamp::SectionComponent < ApplicationComponent
|
|||
"h#{header_section.level + 1}"
|
||||
end
|
||||
|
||||
# if two headers follows each others [h1, [h2, c]]
|
||||
# the first one must not be contained in fieldset
|
||||
# so we make the tree not fillable
|
||||
def fillable?
|
||||
false
|
||||
end
|
||||
|
||||
def split_section_champ(node)
|
||||
case node
|
||||
when EditableChamp::SectionComponent
|
||||
|
@ -55,8 +48,4 @@ class EditableChamp::SectionComponent < ApplicationComponent
|
|||
def first_champ_is_an_header_section?
|
||||
header_section.present?
|
||||
end
|
||||
|
||||
def any_champ_fillable?
|
||||
tail.any? { _1&.fillable? }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,19 +1,24 @@
|
|||
- if render_within_fieldset?
|
||||
= tag.fieldset(class: "reset-#{tag_for_depth} fr-m-0 fr-p-0") do
|
||||
= tag.legend do
|
||||
.fr-fieldset__element{ class: class_names("fr-my-0" => render_within_fieldset?) }
|
||||
%fieldset.fr-fieldset.fr-my-0{ class: "reset-#{tag_for_depth}" }
|
||||
%legend.fr-fieldset__legend
|
||||
= render EditableChamp::HeaderSectionComponent.new(champ: header_section)
|
||||
- splitted_tail.each do |section, champ|
|
||||
- if section.present?
|
||||
= render section
|
||||
- else
|
||||
= fields_for champ.input_name, champ do |form|
|
||||
= render EditableChamp::EditableChampComponent.new form: ,champ:
|
||||
.fr-fieldset__element
|
||||
= render EditableChamp::EditableChampComponent.new form:, champ:
|
||||
- else
|
||||
%fieldset.fr-fieldset.fr-my-0
|
||||
- if header_section
|
||||
%div{ class: "reset-#{tag_for_depth}" }= render EditableChamp::HeaderSectionComponent.new(champ: header_section)
|
||||
%legend.fr-fieldset__legend.fr-my-0{ class: "reset-#{tag_for_depth}" }
|
||||
= render EditableChamp::HeaderSectionComponent.new(champ: header_section)
|
||||
- splitted_tail.each do |section, champ|
|
||||
- if section.present?
|
||||
= render section
|
||||
- else
|
||||
= fields_for champ.input_name, champ do |form|
|
||||
= render EditableChamp::EditableChampComponent.new form: ,champ:
|
||||
.fr-fieldset__element
|
||||
= render EditableChamp::EditableChampComponent.new form:, champ:
|
||||
|
|
|
@ -6,8 +6,8 @@ describe EditableChamp::SectionComponent, type: :component do
|
|||
context 'list of champs without an header_section' do
|
||||
let(:champs) { [build(:champ_text), build(:champ_textarea)] }
|
||||
|
||||
it 'does not render fieldset' do
|
||||
expect(page).not_to have_selector("fieldset")
|
||||
it 'render in a fieldset' do
|
||||
expect(page).to have_selector("fieldset", count: 1)
|
||||
end
|
||||
|
||||
it 'renders champs' do
|
||||
|
@ -34,21 +34,21 @@ describe EditableChamp::SectionComponent, type: :component do
|
|||
let(:champs) { [build(:champ_text), build(:champ_header_section_level_1), build(:champ_text)] }
|
||||
|
||||
it 'renders fieldset' do
|
||||
expect(page).to have_selector("fieldset")
|
||||
expect(page).to have_selector("fieldset", count: 2)
|
||||
expect(page).to have_selector("legend h2")
|
||||
end
|
||||
|
||||
it 'renders all champs, one outside fieldset, one within fieldset' do
|
||||
it 'renders all champs, each in its fieldset' do
|
||||
expect(page).to have_selector("input[type=text]", count: 2)
|
||||
expect(page).to have_selector("fieldset input[type=text]", count: 1)
|
||||
expect(page).to have_selector("fieldset > .fr-fieldset__element input[type=text]", count: 2)
|
||||
end
|
||||
end
|
||||
|
||||
context 'list of header_section without champs' do
|
||||
let(:champs) { [build(:champ_header_section_level_1), build(:champ_header_section_level_2), build(:champ_header_section_level_3)] }
|
||||
|
||||
it 'does not render header within fieldset' do
|
||||
expect(page).not_to have_selector("fieldset")
|
||||
it 'render header within fieldset' do
|
||||
expect(page).to have_selector("fieldset > legend", count: 3)
|
||||
expect(page).to have_selector("h2")
|
||||
expect(page).to have_selector("h3")
|
||||
expect(page).to have_selector("h4")
|
||||
|
@ -58,10 +58,10 @@ describe EditableChamp::SectionComponent, type: :component do
|
|||
context 'header_section followed by explication and another fieldset' do
|
||||
let(:champs) { [build(:champ_header_section_level_1), build(:champ_explication), build(:champ_header_section_level_1), build(:champ_text)] }
|
||||
|
||||
it 'render fieldset, header_section (one within fieldset, one outside), also render explication' do
|
||||
it 'render fieldset, header_section, also render explication' do
|
||||
expect(page).to have_selector("h2", count: 2)
|
||||
expect(page).to have_selector("h3") # explication
|
||||
expect(page).to have_selector("fieldset h2", count: 1)
|
||||
expect(page).to have_selector("fieldset > legend > h2", count: 2)
|
||||
expect(page).to have_selector("fieldset input[type=text]", count: 1)
|
||||
end
|
||||
end
|
||||
|
@ -110,4 +110,57 @@ describe EditableChamp::SectionComponent, type: :component do
|
|||
expect(page).to have_selector("fieldset fieldset input[type=text]", count: dossier.champs_public.find(&:repetition?).rows.size)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with complex markup structure' do
|
||||
def check_fieldset_structure(fieldset)
|
||||
expect(fieldset[:class]).to include('fr-fieldset')
|
||||
|
||||
# Vérifie que chaque fr-fieldset a un enfant fr-fieldset__element ou une légende
|
||||
fieldset.all('> *').each do |child|
|
||||
expect(child.tag_name).to be_in(['div', 'legend', 'input'])
|
||||
|
||||
case child.tag_name
|
||||
when 'legend'
|
||||
expect(child[:class]).to include('fr-fieldset__legend')
|
||||
when 'input'
|
||||
expect(child[:type]).to eq("hidden")
|
||||
else
|
||||
expect(child[:class]).to include('fr-fieldset__element')
|
||||
# Vérifie récursivement les fieldsets imbriqués
|
||||
child.all('> fieldset').each do |nested_fieldset|
|
||||
check_fieldset_structure(nested_fieldset)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
let(:champs) {
|
||||
[
|
||||
build(:champ_header_section_level_1),
|
||||
build(:champ_header_section_level_2),
|
||||
build(:champ_header_section_level_3),
|
||||
build(:champ_integer_number),
|
||||
|
||||
build(:champ_header_section_level_3),
|
||||
build(:champ_yes_no),
|
||||
|
||||
build(:champ_header_section_level_2),
|
||||
build(:champ_header_section_level_3),
|
||||
build(:champ_integer_number),
|
||||
|
||||
build(:champ_header_section_level_1),
|
||||
build(:champ_text),
|
||||
build(:champ_header_section_level_2),
|
||||
build(:champ_text)
|
||||
]
|
||||
}
|
||||
|
||||
it 'respect dsfr fieldset hierarchy' do
|
||||
within('.dossier-edit .form') do
|
||||
all('fieldset').each do |fieldset|
|
||||
check_fieldset_structure(fieldset)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue