dsfr-view-components 0.0.1 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +47 -123
  3. data/app/components/dsfr_component/accordion_component/section_component.html.erb +15 -9
  4. data/app/components/dsfr_component/accordion_component/section_component.rb +11 -24
  5. data/app/components/dsfr_component/accordion_component.rb +5 -16
  6. data/app/components/dsfr_component/alert_component.rb +72 -5
  7. data/app/components/dsfr_component/badge_component.rb +30 -0
  8. data/app/components/dsfr_component/base.rb +2 -0
  9. data/app/components/dsfr_component/button_component.rb +63 -0
  10. data/app/components/dsfr_component/header_component/direct_link_component.rb +22 -0
  11. data/app/components/dsfr_component/header_component/direct_link_dropdown_component.rb +34 -0
  12. data/app/components/dsfr_component/header_component/tool_link_component.rb +20 -0
  13. data/app/components/dsfr_component/header_component.html.erb +80 -37
  14. data/app/components/dsfr_component/header_component.rb +17 -135
  15. data/app/components/dsfr_component/modal_component.html.erb +30 -0
  16. data/app/components/dsfr_component/modal_component.rb +33 -0
  17. data/app/components/dsfr_component/stepper_component.html.erb +18 -0
  18. data/app/components/dsfr_component/stepper_component.rb +26 -0
  19. data/app/components/dsfr_component/tag_component.rb +60 -31
  20. data/app/components/dsfr_component/tile_component.html.erb +19 -0
  21. data/app/components/dsfr_component/tile_component.rb +38 -0
  22. data/app/helpers/dsfr_components_helper.rb +17 -19
  23. data/app/helpers/dsfr_link_helper.rb +41 -90
  24. data/lib/dsfr/components/version.rb +1 -1
  25. data/lib/generators/dsfr_component/USAGE +28 -0
  26. data/lib/generators/dsfr_component/dsfr_component_generator.rb +50 -0
  27. data/lib/generators/dsfr_component/templates/component.haml.erb +13 -0
  28. data/lib/generators/dsfr_component/templates/component.rb.erb +32 -0
  29. data/lib/generators/dsfr_component/templates/component_helper.rb.erb +10 -0
  30. data/lib/generators/dsfr_component/templates/component_spec.rb.erb +5 -0
  31. metadata +90 -63
  32. data/app/components/dsfr_component/back_link_component.rb +0 -24
  33. data/app/components/dsfr_component/breadcrumbs_component.html.erb +0 -7
  34. data/app/components/dsfr_component/breadcrumbs_component.rb +0 -51
  35. data/app/components/dsfr_component/cookie_banner_component/message_component.rb +0 -62
  36. data/app/components/dsfr_component/cookie_banner_component.rb +0 -35
  37. data/app/components/dsfr_component/details_component.rb +0 -42
  38. data/app/components/dsfr_component/footer_component.html.erb +0 -49
  39. data/app/components/dsfr_component/footer_component.rb +0 -87
  40. data/app/components/dsfr_component/inset_text_component.rb +0 -28
  41. data/app/components/dsfr_component/notification_banner_component.html.erb +0 -14
  42. data/app/components/dsfr_component/notification_banner_component.rb +0 -93
  43. data/app/components/dsfr_component/pagination_component/adjacent_page.rb +0 -59
  44. data/app/components/dsfr_component/pagination_component/item.rb +0 -77
  45. data/app/components/dsfr_component/pagination_component/next_page.rb +0 -27
  46. data/app/components/dsfr_component/pagination_component/previous_page.rb +0 -21
  47. data/app/components/dsfr_component/pagination_component.rb +0 -129
  48. data/app/components/dsfr_component/panel_component.rb +0 -56
  49. data/app/components/dsfr_component/phase_banner_component.html.erb +0 -6
  50. data/app/components/dsfr_component/phase_banner_component.rb +0 -25
  51. data/app/components/dsfr_component/section_break_component.rb +0 -49
  52. data/app/components/dsfr_component/start_button_component.rb +0 -55
  53. data/app/components/dsfr_component/summary_list_component/action_component.rb +0 -42
  54. data/app/components/dsfr_component/summary_list_component/key_component.rb +0 -23
  55. data/app/components/dsfr_component/summary_list_component/row_component.rb +0 -57
  56. data/app/components/dsfr_component/summary_list_component/value_component.rb +0 -23
  57. data/app/components/dsfr_component/summary_list_component.html.erb +0 -5
  58. data/app/components/dsfr_component/summary_list_component.rb +0 -49
  59. data/app/components/dsfr_component/tab_component.html.erb +0 -11
  60. data/app/components/dsfr_component/tab_component.rb +0 -61
  61. data/app/components/dsfr_component/table_component/body_component.html.erb +0 -5
  62. data/app/components/dsfr_component/table_component/body_component.rb +0 -21
  63. data/app/components/dsfr_component/table_component/caption_component.rb +0 -37
  64. data/app/components/dsfr_component/table_component/cell_component.rb +0 -57
  65. data/app/components/dsfr_component/table_component/head_component.html.erb +0 -5
  66. data/app/components/dsfr_component/table_component/head_component.rb +0 -23
  67. data/app/components/dsfr_component/table_component/row_component.html.erb +0 -5
  68. data/app/components/dsfr_component/table_component/row_component.rb +0 -30
  69. data/app/components/dsfr_component/table_component.html.erb +0 -7
  70. data/app/components/dsfr_component/table_component.rb +0 -35
  71. data/app/components/dsfr_component/warning_text_component.rb +0 -37
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 13a375b911fee2a88bc620482b766be2d3348d0138d56f9f2cb2641f649e8d50
4
- data.tar.gz: 85f677a71346315a8c128f156b32c74b6436528bfa5ed98fcaf490d352fdeb71
3
+ metadata.gz: 26127e695550fca9861568104cb2e15f13f81c77d8ab97788db823215bdcd43e
4
+ data.tar.gz: 90059e2796a0b0e63f6fed13bb9183866dd01ec796d190e342fd9f458d5a1bdf
5
5
  SHA512:
6
- metadata.gz: 6b10dd868701e33699626fa4753fd7a017128f87b91394c72100d24b014c16206e5285ca81778d045c025241c56a6a97805859b6af75d1c946ba917677818dc7
7
- data.tar.gz: e81ae1788e01bc3e24ec2cc07a4ccfd2cf8fef13fd6d6a5a865423cdf584d65a5303c0965681ff2a922e2cb50bc61bbffb3eca87f20c7cf4224bbd51a355ee06
6
+ metadata.gz: f14bbd9482cf8dfa9473d024c388a30db71225c31fcee52bf69d2dfed43802892dc3cfb56e21f1273d187378cf0e905e801ed9092958839ed3ec9329fc58ece9
7
+ data.tar.gz: 30e838fb64e6e0fb1fb11adea4967aaf4cdeed2fc8763d8e46ffe4823f1e3a98c4512e974a001e86fcefe47b113dec303e49e3e7e4517727098edda9439c498f
data/README.md CHANGED
@@ -1,74 +1,73 @@
1
1
  # Composants du DSFR
2
2
 
3
+ [![Tests](https://github.com/betagouv/dsfr-view-components/workflows/Tests/badge.svg)](https://github.com/betagouv/dsfr-view-components/actions?query=workflow%3ATests)
4
+ [![Gem Version](https://badge.fury.io/rb/dsfr-view-components.svg)](https://badge.fury.io/rb/dsfr-view-components)
5
+ [![Gem](https://img.shields.io/gem/dt/dsfr-view-components?logo=rubygems)](https://rubygems.org/gems/dsfr-view-components)
6
+ [![GitHub license](https://img.shields.io/github/license/betagouv/dsfr-view-components)](https://github.com/betagouv/dsfr-view-components/blob/main/LICENSE)
7
+ [![Rails](https://img.shields.io/badge/Rails-6.1.5%20%E2%95%B1%207.0.3-E16D6D)](https://weblog.rubyonrails.org/releases/)
8
+ [![Ruby](https://img.shields.io/badge/Ruby-2.7.6%20%20%E2%95%B1%203.0.3%20%20%E2%95%B1%203.1.2-E16D6D)](https://www.ruby-lang.org/en/downloads/)
9
+
10
+ [![Design Système de lʼÉtat](https://img.shields.io/badge/Design%20Système%20de%20lʼÉtat-1.8.4-brightgreen)](https://www.systeme-de-design.gouv.fr/)
11
+
3
12
  Cette gem fournit des composants pour le Design Système de l'État (DSFR) en s'appuyant sur le [framework ViewComponent](https://github.com/ViewComponent/view_component).
4
13
 
5
14
  C'est un fork de [govuk-components](https://github.com/DFE-Digital/govuk-components) qui propose l'équivalent pour le GOV.UK Design System.
6
15
 
7
- ⚠️ Cette gem est en cours de développement et n'est pas adaptée à un usage en production. N'hésitez pas à contribuer pour nous aider à avancer !
8
16
 
9
- [![Tests](https://github.com/betagouv/dsfr-view-components/workflows/Tests/badge.svg)](https://github.com/betagouv/dsfr-view-components/actions?query=workflow%3ATests)
17
+ ## Développement en cours ⚠️
10
18
 
11
- <!--
12
- [![Maintainability](https://api.codeclimate.com/v1/badges/cbcbc140f300b920d833/maintainability)](https://codeclimate.com/github/DFE-Digital/govuk-components/maintainability)
13
- [![Gem Version](https://badge.fury.io/rb/govuk-components.svg)](https://badge.fury.io/rb/govuk-components)
14
- [![Gem](https://img.shields.io/gem/dt/govuk-components?logo=rubygems)](https://rubygems.org/gems/govuk-components)
15
- [![Test Coverage](https://api.codeclimate.com/v1/badges/cbcbc140f300b920d833/test_coverage)](https://codeclimate.com/github/DFE-Digital/govuk-components/test_coverage)
16
- [![GitHub license](https://img.shields.io/github/license/DFE-Digital/govuk-components)](https://github.com/DFE-Digital/govuk-components/blob/main/LICENSE)
17
- [![GOV.UK Design System Version](https://img.shields.io/badge/GOV.UK%20Design%20System-4.3.0-brightgreen)](https://design-system.service.gov.uk)
18
- [![Rails](https://img.shields.io/badge/Rails-6.1.5%20%E2%95%B1%207.0.3-E16D6D)](https://weblog.rubyonrails.org/releases/)
19
- [![Ruby](https://img.shields.io/badge/Ruby-2.7.6%20%20%E2%95%B1%203.0.3%20%20%E2%95%B1%203.1.2-E16D6D)](https://www.ruby-lang.org/en/downloads/)
19
+ Cette gem est en cours de développement et n'est pas encore
20
+ recommandée pour un usage en production.
20
21
 
21
- This gem provides a suite of reusable components for the [GOV.UK Design System](https://design-system.service.gov.uk/). It is intended to provide a lightweight alternative to the [GOV.UK Publishing Components](https://github.com/alphagov/dsfr_publishing_components) library and is built with GitHub’s [ViewComponent](https://github.com/github/view_component) framework.
22
+ N'hésitez pas à contribuer pour nous aider à avancer, un générateur de
23
+ composant est même fourni pour vous faciliter la tâche :
22
24
 
23
- It aims to implement the functionality from the original Nunjucks macros in a way that will feel more familiar to Rails developers. Blocks are preferred over strings of HTML, beneath the surface each component is just a Ruby object, everything is inheritable and overrideable.
25
+ ```sh
26
+ bin/rails g dsfr_component FancyButton --params title:String count:Integer
27
+ ```
24
28
 
25
29
  ## Documentation
26
30
 
27
- The gem comes with [a full guide](https://govuk-components.netlify.app/) that
28
- covers most aspects of day-to-day use, along with code and output examples. The
29
- examples in the guide (and the guide itself) are built using the components,
30
- so it will always be up to date.
31
+ Un [guide complet est disponible](https://betagouv.github.io/dsfr-view-components/). Il contient des instructions pour l'installation et l'usage de cette gem. Les exemples présents éxecutent le code et seront donc toujours à jour.
31
32
 
32
- [![Netlify Status](https://api.netlify.com/api/v1/badges/d40a5a0a-b086-4c35-b046-97fbcbf9f219/deploy-status)](https://app.netlify.com/sites/govuk-components/deploys)
33
+ ## Installation
33
34
 
34
- -->
35
+ Pour utiliser cette gem dans votre application Rails, il faut ajouter cette ligne dans `config/application.rb`:
36
+
37
+ ```ruby
38
+ require "dsfr/components"
39
+ ```
35
40
 
36
41
  ## Composants disponibles
37
42
 
38
43
  Cette gem a pour but de supporter tous les composants proposés par le Design Système de l'État hormis ceux concernant les formulaires. Ceux-ci seront fournis dans une gem indépendante dans le futur.
39
44
 
40
- Les composants disponibles sont :
45
+ 10/36 composants sont disponibles :
41
46
 
42
- - [ ] Accordéon - Accordion
43
- - [ ] Ajout de fichier - File upload
44
- - [ ] Alertes - Alert
45
- - [ ] Badge
47
+ - [x] Accordéon - Accordion
48
+ - [x] Alertes - Alert
49
+ - [x] Badge
46
50
  - [ ] Bandeau d'information importante
47
51
  - [ ] Barre de recherche - Search bar
48
- - [ ] Boutons - Buttons
52
+ - [x] Boutons - Buttons
49
53
  - [ ] Groupe de bouton
50
54
  - [ ] Bouton FranceConnect
51
- - [ ] Boutons radio
52
- - [ ] Boutons radio 'riches'
53
- - [ ] Case à cocher - Checkbox
54
55
  - [ ] Cartes - Cards
55
- - [ ] Champ de saisie - Input
56
56
  - [ ] Citation - Quote
57
57
  - [ ] Contenu médias - Responsive médias
58
- - [ ] En-tête - Header
58
+ - [x] En-tête - Header
59
59
  - [ ] Fil d'Ariane - Breadcrumb
60
60
  - [ ] Gestionnaire de consentement - Consent banner
61
61
  - [ ] Icônes de favoris - Favicons
62
- - [ ] Indicateur d'étape
62
+ - [x] Indicateur d'étape - Stepper
63
63
  - [ ] Interrupteur - Toggle switch
64
64
  - [ ] Lettre d'information et réseaux sociaux - Newsletter &amp; Follow us
65
- - [ ] Liens - Links
65
+ - [x] Liens - Links
66
66
  - [ ] Liens d'évitement - Skiplinks
67
- - [ ] Liste déroulante - Select
68
67
  - [ ] Menu latéral - Side menu
69
68
  - [ ] Mise en avant - Call out
70
69
  - [ ] Mise en exergue - Highlight
71
- - [ ] Modale - Modal
70
+ - [x] Modale - Modal
72
71
  - [ ] Navigation principale - Main navigation
73
72
  - [ ] Onglets - Tabs
74
73
  - [ ] Pagination
@@ -78,9 +77,9 @@ Les composants disponibles sont :
78
77
  - [ ] Sélecteur de langue
79
78
  - [ ] Sommaire - Summary
80
79
  - [ ] Tableau - Table
81
- - [ ] Tag
80
+ - [x] Tag
82
81
  - [ ] Téléchargement de fichier
83
- - [ ] Tuile - Tile
82
+ - [x] Tuile - Tile
84
83
 
85
84
  <!--
86
85
  This library also provides helpers for creating [links](https://govuk-components.netlify.app/helpers/link),
@@ -88,92 +87,9 @@ This library also provides helpers for creating [links](https://govuk-components
88
87
  and [back to top links](https://govuk-components.netlify.app/helpers/back-to-top-link).
89
88
  -->
90
89
 
91
- <!--
92
- ## Alternative syntax
93
-
94
- All of the components can be rendered in two ways:
95
-
96
- * directly using Rails’ `#render` method:
97
-
98
- ```erb
99
- <%= render DsfrComponent::WarningTextComponent.new do %>
100
- A serious warning
101
- <% end %>
102
- ```
103
-
104
- * via the helper wrapper:
105
-
106
- ```erb
107
- <%= dsfr_warning_text do %>
108
- A serious warning
109
- <% end %>
110
- ```
111
-
112
- The naming convention for helpers is `dsfr_` followed by the component’s name in snake case. You can see the full list in [DsfrComponentsHelper](app/helpers/dsfr_components_helper.rb).
113
-
114
- ## Example use
115
-
116
- This library allows components to be rendered with Rails’ `render` method or via the provided helpers. Here we’ll use the `dsfr_tabs` to render three tabbed sections:
117
-
118
- ```erb
119
- <%= dsfr_tabs(title: 'Days of the week') do |component| %>
120
- <% component.tab(label: 'Monday') do %>
121
- <p>Monday’s child is fair of face</p>
122
- <% end %>
123
-
124
- <% component.tab(label: 'Tuesday') do %>
125
- <p>Tuesday’s child is full of grace</p>
126
- <% end %>
127
-
128
- <% component.tab(label: 'Wednesday') do %>
129
- <p>Wednesday’s child is full of woe</p>
130
- <% end %>
131
- <% end %>
132
- ```
133
-
134
- Here are the rendered tabs:
90
+ ## Services utilisant cette gem
135
91
 
136
- ![Tabs preview](docs/images/tabs.png)
137
-
138
- For examples on usage see the [guide page](https://govuk-components.netlify.app/).
139
-
140
- ## Setup
141
-
142
- Add this line to your `config/application.rb`:
143
-
144
- ```ruby
145
- require "govuk/components"
146
- ```
147
-
148
- ## Services using this library
149
-
150
- * [Apply for teacher training](https://github.com/DFE-Digital/apply-for-teacher-training)
151
- * [Find postgraduate teacher training](https://github.com/DFE-Digital/find-teacher-training)
152
- * [Get help with technology](https://github.com/DFE-Digital/get-help-with-tech)
153
- * [Publish teacher training courses](https://github.com/DFE-Digital/publish-teacher-training)
154
- * [Register trainee teachers](https://github.com/DFE-Digital/register-trainee-teachers)
155
- * [Teaching Vacancies](https://github.com/DFE-Digital/teaching-vacancies)
156
-
157
- ## Installation
158
-
159
- Ajouter cette ligne à votre Gemfile:
160
-
161
- ```ruby
162
- gem 'dsfr-components'
163
- ```
164
-
165
- And then execute:
166
-
167
- ```sh
168
- bundle
169
- ```
170
-
171
- Or install it yourself as:
172
-
173
- ```sh
174
- gem install govuk-components
175
- ```
176
- -->
92
+ - [Collectif Objets](https://collectif-objets.beta.gouv.fr/) - [code source](https://github.com/betagouv/collectif-objets)
177
93
 
178
94
  ## Contribuer
179
95
 
@@ -191,7 +107,12 @@ bundle install
191
107
  bundle exec rspec spec
192
108
  ```
193
109
 
194
- Lancer le guide de documentation :
110
+ Pour développer avec les tests en continu :
111
+ ```sh
112
+ bundle exec guard
113
+ ```
114
+
115
+ Lancer le guide de documentation :
195
116
 
196
117
  ```sh
197
118
  make watch-guide
@@ -207,7 +128,10 @@ bundle exec rails server
207
128
 
208
129
  Déployer une nouvelle version de la gem :
209
130
 
210
- TODO
131
+ ```sh
132
+ VERSION=1.3.2 make deploy_gem
133
+ ```
134
+
211
135
 
212
136
  ## Licence
213
137
 
@@ -1,11 +1,17 @@
1
- <%= tag.div(id: id(suffix: 'section'), **html_attributes) do %>
2
- <div class="govuk-accordion__section-header">
3
- <%= content_tag(heading_level, class: "govuk-accordion__section-heading") do %>
4
- <%= tag.span(heading_content, id: id, class: "govuk-accordion__section-button", aria: { expanded: expanded?, controls: id(suffix: 'content') }) %>
5
- <% end %>
6
- <% if summary_content.present? %>
7
- <%= tag.div(summary_content, id: id(suffix: 'summary'), class: %w(govuk-accordion__section-summary govuk-body)) %>
8
- <% end %>
1
+ <%= tag.section(**html_attributes) do %>
2
+ <h3 class="fr-accordion__title">
3
+ <button
4
+ class="fr-accordion__btn"
5
+ aria-expanded="<%= expanded? ? "true" : "false" %>"
6
+ aria-controls="<%= id %>"
7
+ >
8
+ <%= title %>
9
+ </button>
10
+ </h3>
11
+ <div
12
+ id="<%= id %>"
13
+ class="fr-collapse <%= "fr-collapse--expanded" if expanded? %>"
14
+ >
15
+ <%= content %>
9
16
  </div>
10
- <%= tag.div(content, id: id(suffix: 'content'), class: %w(govuk-accordion__section-content), aria: { labelledby: id }) %>
11
17
  <% end %>
@@ -1,39 +1,26 @@
1
1
  class DsfrComponent::AccordionComponent::SectionComponent < DsfrComponent::Base
2
- attr_reader :heading_text, :summary_text, :expanded, :heading_level
3
-
4
- renders_one :heading_html
5
- renders_one :summary_html
2
+ attr_reader :title, :expanded
6
3
 
7
4
  alias_method :expanded?, :expanded
8
5
 
9
- def initialize(heading_text:, summary_text:, expanded:, heading_level:, classes: [], html_attributes: {})
10
- @heading_text = heading_text
11
- @summary_text = summary_text
12
- @expanded = expanded
13
- @heading_level = heading_level
6
+ # @param title [String] section title
7
+ # @param expanded [Boolean] toggles section folding
8
+ # @param id [String] the HTML id, optional if you want to reuse the anchor
9
+ def initialize(title:, expanded: false, id: nil, classes: [], html_attributes: {})
10
+ @title = title
11
+ @expanded = expanded
12
+ @id = id
14
13
 
15
14
  super(classes: classes, html_attributes: html_attributes)
16
15
  end
17
16
 
18
- def id(suffix: nil)
19
- # generate a random number if we don't have heading_text to avoid attempting
20
- # to parameterize a potentially-huge chunk of HTML
21
- @prefix ||= heading_text&.parameterize || SecureRandom.hex(4)
22
-
23
- [@prefix, suffix].compact.join('-')
24
- end
25
-
26
- def heading_content
27
- heading_html || heading_text || fail(ArgumentError, "no heading_text or heading_html")
28
- end
29
-
30
- def summary_content
31
- summary_html || summary_text
17
+ def id
18
+ @id ||= "accordion-section-#{SecureRandom.hex(4)}"
32
19
  end
33
20
 
34
21
  private
35
22
 
36
23
  def default_attributes
37
- { class: class_names("govuk-accordion__section", "govuk-accordion__section--expanded" => expanded?).split }
24
+ { class: class_names("fr-accordion").split }
38
25
  end
39
26
  end
@@ -1,33 +1,22 @@
1
1
  class DsfrComponent::AccordionComponent < DsfrComponent::Base
2
- renders_many :sections, ->(heading_text: nil, summary_text: nil, expanded: false, classes: [], html_attributes: {}, &block) do
2
+ renders_many :sections, ->(title: nil, expanded: false, id: nil, classes: [], html_attributes: {}, &block) do
3
3
  DsfrComponent::AccordionComponent::SectionComponent.new(
4
4
  classes: classes,
5
5
  expanded: expanded,
6
- heading_level: heading_level, # set once at parent level, passed to all children
7
6
  html_attributes: html_attributes,
8
- summary_text: summary_text,
9
- heading_text: heading_text,
7
+ title: title,
8
+ id: id,
10
9
  &block
11
10
  )
12
11
  end
13
12
 
14
- attr_reader :id, :heading_level
15
-
16
- def initialize(heading_level: 2, classes: [], html_attributes: {})
17
- @heading_level = heading_tag(heading_level)
18
-
13
+ def initialize(classes: [], html_attributes: {})
19
14
  super(classes: classes, html_attributes: html_attributes)
20
15
  end
21
16
 
22
17
  private
23
18
 
24
19
  def default_attributes
25
- { class: %w(govuk-accordion), data: { module: 'govuk-accordion' } }
26
- end
27
-
28
- def heading_tag(level)
29
- fail(ArgumentError, "heading_level must be 1-6") unless level.in?(1..6)
30
-
31
- %(h#{level})
20
+ { class: %w(fr-accordions-group) }
32
21
  end
33
22
  end
@@ -1,22 +1,89 @@
1
1
  class DsfrComponent::AlertComponent < DsfrComponent::Base
2
- attr_reader :title
2
+ TYPES = %i[error success info warning].freeze
3
+ SIZES = %i[sm md].freeze
3
4
 
4
- def initialize(title:, classes: [], html_attributes: {})
5
+ # @param type [Symbol] alert type (and matching color) `:success`, `:info`, `:warning` ou `:error`
6
+ # @param title [String] alert title. cannot be set in size `:sm`
7
+ # @param size [Symbol] alert size : `:md` (default) or `:sm`
8
+ # @param close_button [Boolean] display a close button to remove the alert
9
+ # @note in size MD the title is required but the content is optional. In size SM there should be not title but the content is required
10
+ def initialize(type:, title: nil, size: :md, close_button: false, classes: [], html_attributes: {})
5
11
  @title = title
12
+ @type = type
13
+ @size = size
14
+ @close_button = close_button
6
15
 
7
16
  super(classes: classes, html_attributes: html_attributes)
8
17
  end
9
18
 
10
19
  def call
20
+ raise ArgumentError, "SM alerts cannot have titles but must have a content" if @size == :sm && (@title.present? || content.blank?)
21
+ raise ArgumentError, "MD Alerts must have a title" if @size == :md && @title.blank?
22
+
11
23
  tag.div(**html_attributes) do
12
- tag.h3(class: "fr-alert__title") { title }
13
- tag.p { content }
24
+ safe_join([title_tag, content_tag, close_button_tag])
14
25
  end
15
26
  end
16
27
 
17
28
  private
18
29
 
30
+ attr_reader :title, :type, :size, :close_button
31
+
19
32
  def default_attributes
20
- { class: %w(fr-alert) }
33
+ { class: %w(fr-alert) + [type_class, size_class].compact }
34
+ end
35
+
36
+ def title_tag
37
+ return nil if title.blank?
38
+
39
+ tag.h3(class: "fr-alert__title") { title }
40
+ end
41
+
42
+ def content_tag
43
+ return nil if content.blank?
44
+
45
+ tag.p { content }
46
+ end
47
+
48
+ def close_button_tag
49
+ return nil unless close_button
50
+
51
+ tag.button(
52
+ class: "fr-btn--close fr-btn",
53
+ title: "Masquer le message",
54
+ onclick: "const alert = this.parentNode; alert.parentNode.removeChild(alert)"
55
+ ) do
56
+ "Masquer le message"
57
+ end
58
+ end
59
+
60
+ def type_class
61
+ fail(ArgumentError, type_error_message) unless valid_type?
62
+
63
+ "fr-alert--#{type}"
64
+ end
65
+
66
+ def valid_type?
67
+ type.in?(TYPES)
68
+ end
69
+
70
+ def type_error_message
71
+ "invalid alert type #{type}, supported types are #{TYPES.to_sentence}"
72
+ end
73
+
74
+ def size_class
75
+ return nil if size == :md
76
+
77
+ fail(ArgumentError, size_error_message) unless valid_size?
78
+
79
+ "fr-alert--#{size}"
80
+ end
81
+
82
+ def valid_size?
83
+ size.in?(SIZES)
84
+ end
85
+
86
+ def size_error_message
87
+ "invalid alert size #{size}, supported sizes are #{SIZES.to_sentence}"
21
88
  end
22
89
  end
@@ -0,0 +1,30 @@
1
+ module DsfrComponent
2
+ class BadgeComponent < DsfrComponent::Base
3
+ STATUSES = %i[success error info warning new].freeze
4
+
5
+ # @param status [BadgeComponent::STATUSES]
6
+ def initialize(status:, classes: [], html_attributes: {})
7
+ raise(ArgumentError, "`status` should be one of #{STATUSES}") unless STATUSES.include?(status)
8
+
9
+ @status = status
10
+
11
+ classes.push("fr-badge--#{@status}")
12
+
13
+ super(classes: classes, html_attributes: html_attributes)
14
+ end
15
+
16
+ def call
17
+ tag.div(**html_attributes) do
18
+ content
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ attr_reader :status
25
+
26
+ def default_attributes
27
+ { class: 'fr-badge' }
28
+ end
29
+ end
30
+ end
@@ -5,6 +5,8 @@ class DsfrComponent::Base < ViewComponent::Base
5
5
 
6
6
  delegate :config, to: Dsfr::Components
7
7
 
8
+ HEADING_LEVELS = [1, 2, 3, 4, 5, 6].freeze
9
+
8
10
  def initialize(classes:, html_attributes:)
9
11
  if classes.nil?
10
12
  Rails.logger.warn("classes is nil, if no custom classes are needed omit the param")
@@ -0,0 +1,63 @@
1
+ module DsfrComponent
2
+ class ButtonComponent < DsfrComponent::Base
3
+ SIZES = %i[sm md lg].freeze
4
+ ICON_POSITIONS = %i[left right].freeze
5
+ ICON_LEVELS = %i[primary secondary tertiary].freeze
6
+
7
+ # @param label [String] Le label du bouton (optionnel si un icône présent)
8
+ # @param icon [String] Le nom de l’icône à afficher (exemple `arrow-right-line`) (optionnel)
9
+ # @param icon_position [String] Position de l’icône : :left (défaut) ou :right (optionnel)
10
+ # @param title [String] Le titre du bouton permettant d’afficher une infobulle (optionnel)
11
+ # @param level [String] Le niveau du bouton : :primary (défaut), :secondary ou :tertiary (optionnel)
12
+ # @param size [String] La taille du bouton : :sm, :md (défaut), :lg (optionnel)
13
+ def initialize(label: nil, title: nil, icon: nil, icon_position: :left, level: nil, size: nil, classes: [], html_attributes: {})
14
+ @label = label
15
+ @title = title
16
+ @icon = icon
17
+ @icon_position = icon_position
18
+ @level = level
19
+ @outline = outline
20
+ @size = size
21
+
22
+ validate_size
23
+ validate_icon_position
24
+ validate_level
25
+ validate_label
26
+
27
+ super(classes: classes, html_attributes: html_attributes)
28
+ end
29
+
30
+ def call
31
+ tag.button(**html_attributes) { label }
32
+ end
33
+
34
+ private
35
+
36
+ attr_reader :label, :icon, :icon_position, :level, :outline, :size
37
+
38
+ def default_attributes
39
+ classes = ["fr-btn"]
40
+ classes << "fr-btn--#{level}" if level.present?
41
+ classes << "fr-btn--#{size}" if size.present?
42
+ classes << "fr-icon-#{icon}" if icon.present?
43
+ classes << "fr-btn--icon-#{icon_position}" if icon.present? && label.present?
44
+ { class: classes }
45
+ end
46
+
47
+ def validate_size
48
+ raise(ArgumentError, "`size` should be one of #{SIZES}") if size.present? && SIZES.exclude?(size)
49
+ end
50
+
51
+ def validate_icon_position
52
+ raise(ArgumentError, "`icon_position` should be one of #{ICON_POSITIONS}") if icon_position.present? && ICON_POSITIONS.exclude?(icon_position)
53
+ end
54
+
55
+ def validate_level
56
+ raise(ArgumentError, "`level` should be one of #{ICON_LEVELS}") if level.present? && ICON_LEVELS.exclude?(level)
57
+ end
58
+
59
+ def validate_label
60
+ raise(ArgumentError, "`label` is required unless an icon is specified") if label.blank? && icon.blank?
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,22 @@
1
+ class DsfrComponent::HeaderComponent::DirectLinkComponent < DsfrComponent::Base
2
+ def initialize(title:, path:, active: false, classes: [], html_attributes: {})
3
+ @title = title
4
+ @path = path
5
+ @active = active
6
+
7
+ super(classes: classes, html_attributes: html_attributes)
8
+ end
9
+
10
+ def call
11
+ tag.a(title, **html_attributes)
12
+ end
13
+
14
+ private
15
+
16
+ attr_reader :title, :path, :active
17
+
18
+ def default_attributes
19
+ { href: path, class: 'fr-nav__link', target: "_self" } \
20
+ .merge(active ? { "aria-current": 'page' } : {})
21
+ end
22
+ end
@@ -0,0 +1,34 @@
1
+ class DsfrComponent::HeaderComponent::DirectLinkDropdownComponent < DsfrComponent::Base
2
+ renders_many :links, DsfrComponent::HeaderComponent::DirectLinkComponent
3
+
4
+ def initialize(title:, active: false, classes: [], html_attributes: {})
5
+ @title = title
6
+ @active = active
7
+
8
+ super(classes: classes, html_attributes: html_attributes)
9
+ end
10
+
11
+ def call
12
+ tag.button(title, **html_attributes) +
13
+ tag.div(class: 'fr-collapse fr-menu', id: menu_id) do
14
+ tag.ul(class: 'fr-menu__list') do
15
+ links.map do |link|
16
+ tag.li link.call
17
+ end.join.html_safe
18
+ end
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ attr_reader :title, :active
25
+
26
+ def default_attributes
27
+ { class: 'fr-nav__btn', "aria-expanded": "false", "aria-controls": menu_id } \
28
+ .merge(active ? { "aria-current": 'true' } : {})
29
+ end
30
+
31
+ def menu_id
32
+ @menu_id ||= "menu-#{title.parameterize}"
33
+ end
34
+ end
@@ -0,0 +1,20 @@
1
+ class DsfrComponent::HeaderComponent::ToolLinkComponent < DsfrComponent::Base
2
+ def initialize(title:, path:, classes: [], html_attributes: {})
3
+ @title = title
4
+ @path = path
5
+
6
+ super(classes: classes, html_attributes: html_attributes)
7
+ end
8
+
9
+ def call
10
+ tag.a title, href: path, **html_attributes
11
+ end
12
+
13
+ private
14
+
15
+ attr_reader :title, :path
16
+
17
+ def default_attributes
18
+ { class: 'fr-btn' }
19
+ end
20
+ end