dsfr-view-components 3.1 → 4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6ad464710e4c2bcddb1c49cab5cbc7fe7dac3508dc90e09b55be83adaf0302fc
4
- data.tar.gz: a2c78fd736e9a21d0953e7205c9c0d62c3d9027d256d60035b0556da0e3de72a
3
+ metadata.gz: 1d311caf744ed3223836fc43f8e70b51666992df4c2b2f10f43ac8e302baf115
4
+ data.tar.gz: 7cdd00c96f50f984230622d24a138f2a46375ba5819daefa8e400ef65fb7c93e
5
5
  SHA512:
6
- metadata.gz: c3728eb72aeee052f246550071ec38f2f11dd7194a9ebfe001fe8dbef41e02494ec983626a262e9ef0b25dca64e1c2b48eecdd5be69260e9bb515f3f06ad6466
7
- data.tar.gz: f08bdd10f57d02d956c128ff65304829488a4fe7d41138deeeafe8e15ac72bdd9f0d95803a6b08e1313aa1d9dff8c21bf69a3954d785f57aa3f4e3936ba48acd
6
+ metadata.gz: 0ebe93f69a0cb26daf0bb4900c0c525a2e817cec21c748d8f9ddfa4bf7aa30bfe518b0a4163ae709f7af2a8888b90ea2d7961a71c4f33374f34595538878737d
7
+ data.tar.gz: f8ca4ff1f611861c3f60962a02d24eab0d1461b934fbf6576eaaee1b2b9f90f8a11332836dfadfba7c6fcfbc8d8f858787fb99bcfe3c18a5e4834298471d82d1
@@ -1,6 +1,7 @@
1
1
  <%= tag.section(**html_attributes) do %>
2
- <%= tag.send(starting_header_tag, class: "fr-accordion__title") do %>
2
+ <%= tag.send(header_tag, class: "fr-accordion__title") do %>
3
3
  <button
4
+ type="button"
4
5
  class="fr-accordion__btn"
5
6
  aria-expanded="<%= expanded? ? "true" : "false" %>"
6
7
  aria-controls="<%= id %>"
@@ -1,7 +1,7 @@
1
1
  class DsfrComponent::AccordionComponent::SectionComponent < DsfrComponent::Base
2
2
  include DsfrComponent::Traits::HeaderSizeable
3
3
 
4
- attr_reader :title, :expanded, :starting_header_level
4
+ attr_reader :title, :expanded
5
5
 
6
6
  alias_method :expanded?, :expanded
7
7
 
@@ -10,7 +10,7 @@ class DsfrComponent::AccordionComponent::SectionComponent < DsfrComponent::Base
10
10
  # @param id [String] the HTML id, optional if you want to reuse the anchor
11
11
  def initialize(
12
12
  title:,
13
- starting_header_level:,
13
+ header_level:,
14
14
  expanded: false,
15
15
  id: nil,
16
16
  html_attributes: {}
@@ -18,7 +18,7 @@ class DsfrComponent::AccordionComponent::SectionComponent < DsfrComponent::Base
18
18
  @title = title
19
19
  @expanded = expanded
20
20
  @id = id
21
- @starting_header_level = starting_header_level
21
+ self.header_level = header_level
22
22
 
23
23
  super(html_attributes: html_attributes)
24
24
  end
@@ -7,13 +7,13 @@ class DsfrComponent::AccordionComponent < DsfrComponent::Base
7
7
  html_attributes: html_attributes,
8
8
  title: title,
9
9
  id: id,
10
- starting_header_level: starting_header_level,
10
+ header_level: header_level,
11
11
  &block
12
12
  )
13
13
  end
14
14
 
15
- def initialize(html_attributes: {}, starting_header_level: nil)
16
- @starting_header_level = starting_header_level
15
+ def initialize(html_attributes: {}, header_level: nil)
16
+ self.header_level = header_level
17
17
 
18
18
  super(html_attributes: html_attributes)
19
19
  end
@@ -9,7 +9,7 @@ class DsfrComponent::AlertComponent < DsfrComponent::Base
9
9
  # @param size [AlertComponent::SIZES]
10
10
  # @param close_button [Boolean] contrôle l'affichage d'un bouton de fermeture
11
11
  # @param icon_name [String] un nom d'icône à afficher, seulement disponible pour le type par défaut
12
- # @param starting_header_level [Integer] Le niveau de titre
12
+ # @param header_level [Integer] Le niveau de titre
13
13
  # @note La taille `:md` requiert un titre mais le contenu est
14
14
  # optionel ; la taille `sm` requiert un contenu, mais pas de titre.
15
15
  def initialize(
@@ -18,7 +18,7 @@ class DsfrComponent::AlertComponent < DsfrComponent::Base
18
18
  size: :md,
19
19
  close_button: false,
20
20
  icon_name: nil,
21
- starting_header_level: nil,
21
+ header_level: nil,
22
22
  html_attributes: {}
23
23
  )
24
24
  @title = title
@@ -26,7 +26,7 @@ class DsfrComponent::AlertComponent < DsfrComponent::Base
26
26
  @size = size
27
27
  @close_button = close_button
28
28
  @icon_name = icon_name
29
- @starting_header_level = starting_header_level
29
+ self.header_level = header_level
30
30
 
31
31
  super(html_attributes: html_attributes)
32
32
  end
@@ -77,7 +77,7 @@ private
77
77
  def title_tag
78
78
  return nil if title.blank?
79
79
 
80
- tag.send(starting_header_tag, class: "fr-alert__title") { title }
80
+ tag.send(header_tag, class: "fr-alert__title") { title }
81
81
  end
82
82
 
83
83
  def content_tag
@@ -8,23 +8,23 @@ module DsfrComponent
8
8
 
9
9
  # @param title [String] Le titre de la mise en avant
10
10
  # @param icon_name [String] Le nom de l’icône à afficher (exemple `arrow-right-line`), ou `:none` pour la désactiver (optionnel)
11
- # @param starting_header_level [Integer] Le niveau de titre (optionnel)
11
+ # @param header_level [Integer] Le niveau de titre (optionnel)
12
12
  def initialize(
13
13
  title:,
14
14
  icon_name: "information-line",
15
- starting_header_level: nil,
15
+ header_level: nil,
16
16
  html_attributes: {}
17
17
  )
18
18
  @title = title
19
19
  @icon_name = icon_name
20
- @starting_header_level = starting_header_level
20
+ self.header_level = header_level
21
21
 
22
22
  super(html_attributes: html_attributes)
23
23
  end
24
24
 
25
25
  def call
26
26
  tag.div(**html_attributes) do
27
- concat content_tag(starting_header_tag, @title, class: 'fr-callout__title')
27
+ concat content_tag(header_tag, @title, class: 'fr-callout__title')
28
28
 
29
29
  concat content_tag(:p, content, class: 'fr-callout__text')
30
30
 
@@ -0,0 +1,20 @@
1
+ <%= tag.li(class: "fr-sidemenu__item", **html_attributes) do %>
2
+ <% if sub_items.empty? %>
3
+ <% if @current_page %>
4
+ <a href="<%= path %>" class="fr-sidemenu__link" aria-current="page"><%= title %></a>
5
+ <% else %>
6
+ <a href="<%= path %>" class="fr-sidemenu__link"><%= title %></a>
7
+ <% end %>
8
+ <% else %>
9
+ <button type="button" class="fr-sidemenu__btn" aria-expanded="<%= expanded? ? "true" : "false" %>" aria-controls="sidemenu-<%= object_id %>">
10
+ <%= title %>
11
+ </button>
12
+ <div class="fr-collapse<%= " fr-collapse--expanded" if expanded? %>" id="sidemenu-<%= object_id %>">
13
+ <ul class="fr-sidemenu__list">
14
+ <% sub_items.each do |sub_item| %>
15
+ <%= sub_item %>
16
+ <% end %>
17
+ </ul>
18
+ </div>
19
+ <% end %>
20
+ <% end %>
@@ -0,0 +1,33 @@
1
+ class DsfrComponent::SideMenuComponent::ItemComponent < DsfrComponent::Base
2
+ MAX_LEVEL = 3
3
+
4
+ renders_many :sub_items, ->(title:, path:, current_page: false, expanded: false, html_attributes: {}) {
5
+ DsfrComponent::SideMenuComponent::ItemComponent.new(title:, path:, current_page:, expanded:, level: @level + 1, html_attributes:)
6
+ }
7
+
8
+ # @param title [String] title of the side menu item
9
+ # @param path [String] path of the side menu item
10
+ # @param current_page [Boolean] active current page style
11
+ # @param expanded [Boolean] toggles sub menu folding
12
+ # @param level [Integer] nesting level (1-3), automatically set for sub_items
13
+ def initialize(title:, path:, current_page: false, expanded: false, level: 1, html_attributes: {})
14
+ raise ArgumentError, "Le menu latéral ne supporte pas plus de #{MAX_LEVEL} niveaux" if level > MAX_LEVEL
15
+
16
+ @title = title
17
+ @path = path
18
+ @current_page = current_page
19
+ @expanded = expanded
20
+ @level = level
21
+
22
+ super(html_attributes: html_attributes)
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :title, :path, :expanded
28
+ alias_method :expanded?, :expanded
29
+
30
+ def default_attributes
31
+ { class: 'fr-sidemenu__item' }
32
+ end
33
+ end
@@ -0,0 +1,15 @@
1
+ <%= tag.nav(**html_attributes) do %>
2
+ <div class="fr-sidemenu__inner">
3
+ <button type="button" class="fr-sidemenu__btn" aria-expanded="false" aria-controls="sidemenu-collapse-<%= object_id %>"><%= title %></button>
4
+ <div class="fr-collapse" id="sidemenu-collapse-<%= object_id %>">
5
+ <% if title %>
6
+ <p class="fr-sidemenu__title" id="sidemenu-title-<%= object_id %>"><%= title %></p>
7
+ <% end %>
8
+ <ul class="fr-sidemenu__list">
9
+ <% items.each do |item| %>
10
+ <%= item %>
11
+ <% end %>
12
+ </ul>
13
+ </div>
14
+ </div>
15
+ <% end %>
@@ -0,0 +1,20 @@
1
+ module DsfrComponent
2
+ class SideMenuComponent < DsfrComponent::Base
3
+ renders_many :items, "DsfrComponent::SideMenuComponent::ItemComponent"
4
+
5
+ # @param title [String] title of the side menu
6
+ def initialize(title:, html_attributes: {})
7
+ @title = title
8
+
9
+ super(html_attributes:)
10
+ end
11
+
12
+ private
13
+
14
+ attr_reader :title
15
+
16
+ def default_attributes
17
+ { class: 'fr-sidemenu', role: 'navigation', "aria-labelledby": "sidemenu-title-#{object_id}" }
18
+ end
19
+ end
20
+ end
@@ -1,10 +1,10 @@
1
1
  <%= tag.div(**html_attributes) do %>
2
- <h2 class="fr-stepper__title">
2
+ <%= tag.send(header_tag, class: "fr-stepper__title") do %>
3
3
  <%= title %>
4
4
  <span class="fr-stepper__state">
5
5
  Étape <%= value %> sur <%= max %>
6
6
  </span>
7
- </h2>
7
+ <% end %>
8
8
  <div
9
9
  class="fr-stepper__steps"
10
10
  data-fr-current-step="<%= value %>"
@@ -1,14 +1,18 @@
1
1
  module DsfrComponent
2
2
  class StepperComponent < DsfrComponent::Base
3
+ include DsfrComponent::Traits::HeaderSizeable
4
+
3
5
  # @param title [String] Titre de l’étape en cours
4
6
  # @param value [Integer] Numéro de l’étape en cours (commence à 1)
5
7
  # @param max [Integer] Nombre d’étapes total
6
8
  # @param next_title [String] Titre de l’étape suivante (sauf pour la dernière étape)
7
- def initialize(title:, value:, max:, next_title: nil, html_attributes: {})
9
+ # @param header_level [Integer] Niveau du titre
10
+ def initialize(title:, value:, max:, next_title: nil, header_level: 2, html_attributes: {})
8
11
  @title = title
9
12
  @value = value
10
13
  @max = max
11
14
  @next_title = next_title
15
+ self.header_level = header_level
12
16
 
13
17
  raise ArgumentError, "Les étapes doivent aller de 1 jusqu´à 8 au maximum" if @value < 1 || @value > @max || @max > 8
14
18
 
@@ -3,22 +3,35 @@
3
3
  module DsfrComponent
4
4
  module Traits
5
5
  # HeaderSizeable is meant for every component that exhibits a
6
- # header, which level can be overriden via the
7
- # `default_header_level` method. Make sure you store the attribute
8
- # `@starting_header_level` in your component's constructor.
6
+ # header which level can be overriden. Make sure you use the
7
+ # setter (self.header_level) in your component's constructor.
9
8
  module HeaderSizeable
10
9
  DEFAULT_HEADER_LEVEL = 3
11
10
 
12
- def starting_header_level
13
- @starting_header_level || default_header_level
11
+ def header_level
12
+ @header_level || default_header_level
13
+ end
14
+
15
+ def header_level=(level)
16
+ return if level.nil?
17
+
18
+ raise ArgumentError, "Le niveau du titre doit être compris entre 1 et 6" if !correct?(level)
19
+
20
+ @header_level = level
14
21
  end
15
22
 
16
23
  def default_header_level
17
24
  DEFAULT_HEADER_LEVEL
18
25
  end
19
26
 
20
- def starting_header_tag
21
- ["h", starting_header_level].join
27
+ def header_tag
28
+ ["h", header_level].join
29
+ end
30
+
31
+ private
32
+
33
+ def correct?(level)
34
+ level.in?(DsfrComponent::Base::HEADING_LEVELS)
22
35
  end
23
36
  end
24
37
  end
@@ -22,6 +22,8 @@ module DsfrComponentsHelper
22
22
  dsfr_notice: 'DsfrComponent::NoticeComponent',
23
23
  dsfr_search: 'DsfrComponent::SearchComponent',
24
24
  dsfr_proconnect_button: 'DsfrComponent::ProconnectButtonComponent',
25
+ dsfr_side_menu: 'DsfrComponent::SideMenuComponent',
26
+ dsfr_side_menu_item: 'DsfrComponent::SideMenuComponent::ItemComponent',
25
27
  # DO NOT REMOVE: new component mapping here
26
28
  }.freeze
27
29
  HELPER_NAME_TO_CLASS_NAME.each do |name, klass|
@@ -1,5 +1,5 @@
1
1
  module Dsfr
2
2
  module Components
3
- VERSION = '3.1'.freeze
3
+ VERSION = '4.1'.freeze
4
4
  end
5
5
  end
@@ -10,4 +10,4 @@ title: <%= name %>
10
10
  :markdown
11
11
  Le rendu de base du <%= name %>Component
12
12
 
13
- = render('/partials/related-info.haml', links: dsfr_component_doc_links("doc-id", "storybook-id"))
13
+ = render('/partials/related-info.haml', links: dsfr_component_doc_links("doc-id"))
@@ -1,18 +1,18 @@
1
1
  class DsfrComponent::<%= @name %>Component < DsfrComponent::Base
2
2
  <% if options[:params].empty? %>
3
- def initialize(classes: [], html_attributes: {})
4
- super(classes: classes, html_attributes: html_attributes)
3
+ def initialize(html_attributes: {})
4
+ super(html_attributes: html_attributes)
5
5
  end
6
6
  <% else %>
7
7
  <%- options[:params].each do |param, type| -%>
8
8
  # @param <%= param %> [<%= type %>] FIXME: document
9
9
  <%- end -%>
10
- def initialize(<%= options[:params].keys.map { |p| "#{p}:" }.join(", ") %>, classes: [], html_attributes: {})
10
+ def initialize(<%= options[:params].keys.map { |p| "#{p}:" }.join(", ") %>, html_attributes: {})
11
11
  <%- options[:params].keys.each do |param| -%>
12
12
  <%= "@#{param} = #{param}" %>
13
13
  <%- end -%>
14
14
 
15
- super(classes: classes, html_attributes: html_attributes)
15
+ super(html_attributes: html_attributes)
16
16
  end
17
17
  <% end %>
18
18
 
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dsfr-view-components
3
3
  version: !ruby/object:Gem::Version
4
- version: '3.1'
4
+ version: '4.1'
5
5
  platform: ruby
6
6
  authors:
7
7
  - BetaGouv developers
8
+ autorequire:
8
9
  bindir: bin
9
10
  cert_chain: []
10
- date: 2025-06-03 00:00:00.000000000 Z
11
+ date: 2026-01-15 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: html-attributes-utils
@@ -41,16 +42,22 @@ dependencies:
41
42
  name: dsfr-assets
42
43
  requirement: !ruby/object:Gem::Requirement
43
44
  requirements:
44
- - - "~>"
45
+ - - ">="
45
46
  - !ruby/object:Gem::Version
46
47
  version: 1.13.2
48
+ - - "<"
49
+ - !ruby/object:Gem::Version
50
+ version: '1.15'
47
51
  type: :runtime
48
52
  prerelease: false
49
53
  version_requirements: !ruby/object:Gem::Requirement
50
54
  requirements:
51
- - - "~>"
55
+ - - ">="
52
56
  - !ruby/object:Gem::Version
53
57
  version: 1.13.2
58
+ - - "<"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.15'
54
61
  - !ruby/object:Gem::Dependency
55
62
  name: deep_merge
56
63
  requirement: !ruby/object:Gem::Requirement
@@ -356,6 +363,10 @@ files:
356
363
  - app/components/dsfr_component/proconnect_button_component.rb
357
364
  - app/components/dsfr_component/search_component.html.erb
358
365
  - app/components/dsfr_component/search_component.rb
366
+ - app/components/dsfr_component/side_menu_component.html.erb
367
+ - app/components/dsfr_component/side_menu_component.rb
368
+ - app/components/dsfr_component/side_menu_component/item_component.html.erb
369
+ - app/components/dsfr_component/side_menu_component/item_component.rb
359
370
  - app/components/dsfr_component/skiplink_component.html.erb
360
371
  - app/components/dsfr_component/skiplink_component.rb
361
372
  - app/components/dsfr_component/stepper_component.html.erb
@@ -394,6 +405,7 @@ metadata:
394
405
  homepage_uri: https://github.com/betagouv/dsfr-view-components
395
406
  source_code_uri: https://github.com/betagouv/dsfr-view-components
396
407
  rubygems_mfa_required: 'true'
408
+ post_install_message:
397
409
  rdoc_options: []
398
410
  require_paths:
399
411
  - lib
@@ -408,7 +420,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
408
420
  - !ruby/object:Gem::Version
409
421
  version: '0'
410
422
  requirements: []
411
- rubygems_version: 3.6.2
423
+ rubygems_version: 3.5.13
424
+ signing_key:
412
425
  specification_version: 4
413
426
  summary: Composants ViewComponent pour le Système de Design de l'État (DSFR)
414
427
  test_files: []