crown_marketplace_utils 0.1.0.beta.1 → 0.1.0.beta.3

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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +0 -1
  3. data/.rubocop.yml +14 -0
  4. data/Gemfile +0 -4
  5. data/Gemfile.lock +45 -29
  6. data/README.md +44 -1
  7. data/crown_marketplace_utils.gemspec +11 -8
  8. data/lib/crown_marketplace_utils/gov_uk_helper/breadcrumbs.rb +76 -0
  9. data/lib/crown_marketplace_utils/gov_uk_helper/button.rb +130 -0
  10. data/lib/crown_marketplace_utils/gov_uk_helper/details.rb +14 -8
  11. data/lib/crown_marketplace_utils/gov_uk_helper/error_message.rb +18 -11
  12. data/lib/crown_marketplace_utils/gov_uk_helper/field/character_count.rb +193 -0
  13. data/lib/crown_marketplace_utils/gov_uk_helper/field/checkboxes.rb +209 -0
  14. data/lib/crown_marketplace_utils/gov_uk_helper/field/input.rb +160 -0
  15. data/lib/crown_marketplace_utils/gov_uk_helper/field/radios.rb +205 -0
  16. data/lib/crown_marketplace_utils/gov_uk_helper/field/select.rb +166 -0
  17. data/lib/crown_marketplace_utils/gov_uk_helper/field/textarea.rb +127 -0
  18. data/lib/crown_marketplace_utils/gov_uk_helper/field.rb +263 -0
  19. data/lib/crown_marketplace_utils/gov_uk_helper/fieldset.rb +75 -0
  20. data/lib/crown_marketplace_utils/gov_uk_helper/form_group.rb +60 -0
  21. data/lib/crown_marketplace_utils/gov_uk_helper/header.rb +172 -0
  22. data/lib/crown_marketplace_utils/gov_uk_helper/hint.rb +12 -6
  23. data/lib/crown_marketplace_utils/gov_uk_helper/label.rb +97 -0
  24. data/lib/crown_marketplace_utils/gov_uk_helper/notification_banner.rb +139 -0
  25. data/lib/crown_marketplace_utils/gov_uk_helper/pagination.rb +214 -0
  26. data/lib/crown_marketplace_utils/gov_uk_helper/step_by_step_navigation.rb +225 -0
  27. data/lib/crown_marketplace_utils/gov_uk_helper/tag.rb +39 -0
  28. data/lib/crown_marketplace_utils/gov_uk_helper.rb +37 -2
  29. data/lib/crown_marketplace_utils/version.rb +1 -1
  30. data/lib/crown_marketplace_utils.rb +6 -1
  31. metadata +75 -31
  32. data/lib/crown_marketplace_utils/engine.rb +0 -11
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'action_view'
4
+
5
+ module CrownMarketplaceUtils
6
+ module GovUkHelper
7
+ # = GOV.UK label
8
+ #
9
+ # This helper is used for generating the label component from the Government Design Systems
10
+
11
+ module Label
12
+ include ActionView::Context
13
+ include ActionView::Helpers::TagHelper
14
+ include ActionView::Helpers::TextHelper
15
+ include ActionView::Helpers::FormTagHelper
16
+
17
+ # Generates the HTML for the GOV.UK label component
18
+ #
19
+ # @param attribute [String, Symbol] the attribute of the input that requires a label
20
+ # @param label_text [String] the label text, it is ignored if a block is given
21
+ # @param govuk_label_options [Hash] options that will be used in customising the HTML
22
+ #
23
+ # @option govuk_label_options [String] :classes additional CSS classes for the label HTML
24
+ # @option govuk_label_options [Boolean] :is_page_heading (false) if the legend is also the heading it will rendered in a h1
25
+ # @option govuk_label_options [Hash] :attributes ({}) any additional attributes that will added as part of the HTML
26
+ #
27
+ # @yield HTML that will be contained within the 'govuk-label' label
28
+ #
29
+ # @return [ActiveSupport::SafeBuffer] the HTML for the GOV.UK Label
30
+ # which can then be rendered on the page
31
+
32
+ def govuk_label(attribute, label_text = nil, **govuk_label_options)
33
+ _govuk_label(**govuk_label_options) do |govuk_label_classes, govuk_label_attributes|
34
+ label_tag(attribute, class: govuk_label_classes, **govuk_label_attributes) do
35
+ if block_given?
36
+ yield
37
+ else
38
+ concat(label_text)
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ # Generates the HTML for the GOV.UK label component using an ActionView::Helpers::FormBuilder
45
+ #
46
+ # @param form [ActionView::Helpers::FormBuilder] :form the form builder used to create the label
47
+ # @param attribute [String, Symbol] the attribute of the input that requires a label
48
+ # @param label_text [String] the label text, it is ignored if a block is given
49
+ # @param govuk_label_options [Hash] options that will be used in customising the HTML
50
+ #
51
+ # @option (see govuk_label)
52
+ #
53
+ # @yield (see govuk_label)
54
+ #
55
+ # @return (see govuk_label)
56
+
57
+ def govuk_label_with_form(form, attribute, label_text = nil, **govuk_label_options, &block)
58
+ _govuk_label(**govuk_label_options) do |govuk_label_classes, govuk_label_attributes|
59
+ if block_given?
60
+ form.label(attribute, class: govuk_label_classes, **govuk_label_attributes, &block)
61
+ else
62
+ form.label(attribute, label_text, class: govuk_label_classes, **govuk_label_attributes)
63
+ end
64
+ end
65
+ end
66
+
67
+ private
68
+
69
+ # Wrapper method used by {#govuk_label} and {#govuk_label_with_form} to generate the Label HTML
70
+ #
71
+ # @param govuk_label_options [Hash] options that will be used in customising the HTML
72
+ #
73
+ # @option (see govuk_label)
74
+ #
75
+ # @yield the label HTML generated by {#govuk_label} or {#govuk_label_with_form}
76
+ #
77
+ # @yieldparam govuk_label_classes [Array] the classes for the label HTML
78
+ # @yieldparam govuk_label_attributes [Hash] additional attributes that will added as part of the HTML
79
+ #
80
+ # @return (see govuk_label)
81
+
82
+ def _govuk_label(**govuk_label_options)
83
+ govuk_label_classes = ['govuk-label']
84
+ govuk_label_classes << govuk_label_options[:classes]
85
+ govuk_label_options[:attributes] ||= {}
86
+
87
+ label_html = yield(govuk_label_classes, govuk_label_options[:attributes])
88
+
89
+ if govuk_label_options[:is_page_heading]
90
+ tag.h1(label_html, class: 'govuk-label-wrapper')
91
+ else
92
+ label_html
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'action_view'
4
+
5
+ module CrownMarketplaceUtils
6
+ module GovUkHelper
7
+ # = GOV.UK Notification Banner
8
+ #
9
+ # This helper is used for generating the notification banner component from the
10
+ # {https://design-system.service.gov.uk/components/notification-banner GDS - Components - Notification banner}
11
+
12
+ module NotificationBanner
13
+ include ActionView::Context
14
+ include ActionView::Helpers::TagHelper
15
+ include ActionView::Helpers::TextHelper
16
+
17
+ # Generates the HTML for the GOV.UK Notification banner component
18
+ #
19
+ # @param text [String] the text that will be used for the heading in the content section of the banner.
20
+ # It is ignored if a block is given
21
+ # @param success_banner [Boolean] will use the success banner options if this is set to true
22
+ # @param govuk_notification_banner_options [Hash] options that will be used in customising the HTML
23
+ #
24
+ # @option govuk_notification_banner_options [String] :classes additional CSS classes for the notification banner HTML
25
+ # @option govuk_notification_banner_options [String] :title_text ('Important') the title text shown at the top of the banner
26
+ # @option govuk_notification_banner_options [String] :title_id ('govuk-notification-banner-title') the ID for the title text
27
+ # @option govuk_notification_banner_options [String] :role ('region') the role for the banner
28
+ # @option govuk_notification_banner_options [String] :heading_level (2) the heading level for the title text
29
+ # @option govuk_notification_banner_options [Hash] :attributes ({data: { module: 'govuk-notification-banner' }, aria: { labelledby: 'govuk-notification-banner-title' }})
30
+ # any additional attributes that will added as part of the HTML
31
+ #
32
+ # @yield HTML that will be contained within the 'govuk-notification-banner__content' div
33
+ #
34
+ # @return [ActiveSupport::SafeBuffer] the HTML for the GOV.UK Notification banner
35
+ # which can then be rendered on the page
36
+
37
+ def govuk_notification_banner(text = nil, success_banner = false, **govuk_notification_banner_options)
38
+ banner_options = fetch_banner_options(success_banner, govuk_notification_banner_options)
39
+ govuk_notification_banner_classes = fetch_banner_classes(banner_options, govuk_notification_banner_options)
40
+ govuk_notification_banner_attributes = fetch_banner_attributes(banner_options, govuk_notification_banner_options)
41
+
42
+ tag.div(class: govuk_notification_banner_classes, role: banner_options[:role], **govuk_notification_banner_attributes) do
43
+ capture do
44
+ concat(tag.div(class: 'govuk-notification-banner__header') do
45
+ tag.send(:"h#{govuk_notification_banner_options[:heading_level] || 2}", banner_options[:title_text], class: 'govuk-notification-banner__title', id: banner_options[:title_id])
46
+ end)
47
+ concat(tag.div(class: 'govuk-notification-banner__content') do
48
+ if block_given?
49
+ yield
50
+ else
51
+ tag.p(text, class: 'govuk-notification-banner__heading')
52
+ end
53
+ end)
54
+ end
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ # Determines the banner options to be used for {#govuk_notification_banner}
61
+ #
62
+ # @param success_banner [Boolean] will use the success banner options if this is set to true
63
+ # @param govuk_notification_banner_options [Hash] options that will be used in customising the HTML
64
+ #
65
+ # @option govuk_notification_banner_options [String] :title_text ('Important') the title text shown at the top of the banner
66
+ # @option govuk_notification_banner_options [String] :title_id ('govuk-notification-banner-title') the ID for the title text
67
+ # @option govuk_notification_banner_options [String] :role ('region') the role for the banner
68
+ #
69
+ # @return [Hash] contains the following options used in {#govuk_notification_banner}:
70
+ # - +classes+
71
+ # - +title_text+
72
+ # - +title_id+
73
+ # - +role+
74
+
75
+ def fetch_banner_options(success_banner, govuk_notification_banner_options)
76
+ banner_options = DEFAULT_OPTIONS.dup
77
+
78
+ banner_options.merge!(SUCCESS_BANNER_OPTIONS) if success_banner
79
+
80
+ govuk_notification_banner_options.each do |key, value|
81
+ banner_options[key] = value if banner_options.key?(key)
82
+ end
83
+
84
+ banner_options
85
+ end
86
+
87
+ # Determines the banner classes to be used for {#govuk_notification_banner}
88
+ #
89
+ # @param banner_options [Hash] this is the return value from {#fetch_banner_options}
90
+ # @param govuk_notification_banner_options [Hash] options that will be used in customising the HTML
91
+ #
92
+ # @option govuk_notification_banner_options [String] :classes additional CSS classes for the notification banner HTML
93
+ #
94
+ # @return [Array<String>] an array of classes to be used in {#govuk_notification_banner}
95
+
96
+ def fetch_banner_classes(banner_options, govuk_notification_banner_options)
97
+ govuk_notification_banner_classes = ['govuk-notification-banner']
98
+ govuk_notification_banner_classes << govuk_notification_banner_options[:classes]
99
+ govuk_notification_banner_classes << banner_options[:classes]
100
+
101
+ govuk_notification_banner_classes
102
+ end
103
+
104
+ # Default HTML attributes for {#govuk_notification_banner}
105
+ #
106
+ # @param banner_options [Hash] this is the return value from {#fetch_banner_options}
107
+ # @param govuk_notification_banner_options [Hash] options that will be used in customising the HTML
108
+ #
109
+ # @option govuk_notification_banner_options [Hash] :attributes ({data: { module: 'govuk-notification-banner' }, aria: { labelledby: 'govuk-notification-banner-title' }})
110
+ # any additional attributes that will added as part of the HTML
111
+ #
112
+ # @return [Hash] contains the default attributes for {#govuk_notification_banner} and any additional attributes that were passed
113
+
114
+ def fetch_banner_attributes(banner_options, govuk_notification_banner_options)
115
+ govuk_notification_banner_attributes = govuk_notification_banner_options[:attributes] || {}
116
+ (govuk_notification_banner_attributes[:data] ||= {}).merge!({ module: 'govuk-notification-banner' })
117
+ (govuk_notification_banner_attributes[:aria] ||= {}).merge!({ labelledby: banner_options[:title_id] })
118
+
119
+ govuk_notification_banner_attributes
120
+ end
121
+
122
+ # Default options used in normal versions of {#govuk_notification_banner}
123
+
124
+ DEFAULT_OPTIONS = {
125
+ title_text: 'Important',
126
+ title_id: 'govuk-notification-banner-title',
127
+ role: 'region'
128
+ }.freeze
129
+
130
+ # Options specific for the success version of {#govuk_notification_banner}
131
+
132
+ SUCCESS_BANNER_OPTIONS = {
133
+ classes: 'govuk-notification-banner--success',
134
+ title_text: 'Success',
135
+ role: 'alert'
136
+ }.freeze
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,214 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'action_view'
4
+
5
+ module CrownMarketplaceUtils
6
+ module GovUkHelper
7
+ # = GOV.UK Pagination
8
+ #
9
+ # This helper is used for generating the pagination component from the
10
+ # {https://design-system.service.gov.uk/components/pagination GDS - Components - Pagination}
11
+
12
+ module Pagination
13
+ include ActionView::Context
14
+ include ActionView::Helpers::TagHelper
15
+ include ActionView::Helpers::TextHelper
16
+ include ActionView::Helpers::UrlHelper
17
+
18
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
19
+
20
+ # Generates the HTML for the GOV.UK Pagination component
21
+ #
22
+ # @param govuk_pagination_options [Hash] options that will be used in customising the HTML
23
+ #
24
+ # @option govuk_pagination_options [String] :classes additional CSS classes for the pagination HTML
25
+ # @option govuk_pagination_options [Array] :items an array of items for the pagination (see: {govuk_pagination_items})
26
+ # @option govuk_pagination_options [Hash] :previous the previous link (see: {govuk_pagination_previous})
27
+ # @option govuk_pagination_options [Hash] :next the next link (see: {govuk_pagination_next})
28
+ # @option govuk_pagination_options [Hash] :attributes ({role: 'navigation', aria: { label: 'results' }})
29
+ # any additional attributes that will added as part of the HTML
30
+ #
31
+ # @return [ActiveSupport::SafeBuffer] the HTML for the GOV.UK Pagination
32
+ # which can then be rendered on the page
33
+
34
+ def govuk_pagination(**govuk_pagination_options)
35
+ govuk_pagination_classes = ['govuk-pagination']
36
+ govuk_pagination_classes << govuk_pagination_options[:classes]
37
+
38
+ block_is_level = govuk_pagination_options[:items].blank? && (govuk_pagination_options[:next].present? || govuk_pagination_options[:previous].present?)
39
+
40
+ govuk_pagination_classes << 'govuk-pagination--block' if block_is_level
41
+
42
+ (govuk_pagination_options[:attributes] ||= {}).merge({ role: 'navigation' })
43
+ (govuk_pagination_options[:attributes][:aria] ||= {})[:label] ||= 'results'
44
+
45
+ tag.nav(class: govuk_pagination_classes, **govuk_pagination_options[:attributes]) do
46
+ capture do
47
+ concat(govuk_pagination_previous(block_is_level, **govuk_pagination_options[:previous])) if govuk_pagination_options[:previous]
48
+ concat(govuk_pagination_items(govuk_pagination_options[:items])) if govuk_pagination_options[:items]
49
+ concat(govuk_pagination_next(block_is_level, **govuk_pagination_options[:next])) if govuk_pagination_options[:next]
50
+ end
51
+ end
52
+ end
53
+
54
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
55
+
56
+ private
57
+
58
+ # Generates the previous link for {govuk_pagination}
59
+ #
60
+ # @param block_is_level [Boolean] when there are no items, this will be true and will add extra classe
61
+ # to the link to make the next and previous pagination links level
62
+ # @param govuk_pagination_previous_options [Hash] options that will be used in customising the HTML
63
+ #
64
+ # @option govuk_pagination_previous_options [String] :href the URL for the link
65
+ # @option govuk_pagination_previous_options [String] :text ('Previous') the text for the link
66
+ # @option govuk_pagination_previous_options [String] :lable_text additional text for the link when the pagination block is level
67
+ # @option govuk_pagination_previous_options [Hash] :attributes ({}) any additional attributes that will added as part of the HTML
68
+ #
69
+ # @return [ActiveSupport::SafeBuffer] the HTML for the previous link which is used in {govuk_pagination}
70
+
71
+ def govuk_pagination_previous(block_is_level, **govuk_pagination_previous_options)
72
+ govuk_pagination_previous_classes = ['govuk-pagination__link-title']
73
+ govuk_pagination_previous_classes << 'govuk-pagination__link-title--decorated' if block_is_level && !govuk_pagination_previous_options[:lable_text]
74
+
75
+ tag.div(class: 'govuk-pagination__prev') do
76
+ link_to(govuk_pagination_previous_options[:href], class: 'govuk-link govuk-pagination__link', rel: 'prev', **(govuk_pagination_previous_options[:attributes] || {})) do
77
+ capture do
78
+ concat(govuk_pagination_icon(:prev))
79
+ concat(tag.span(govuk_pagination_previous_options[:text] || 'Previous', class: govuk_pagination_previous_classes))
80
+ concat(govuk_pagination_icon_label_text(block_is_level, govuk_pagination_previous_options[:lable_text]))
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ # Generates the next link for {govuk_pagination}
87
+ #
88
+ # @param block_is_level [Boolean] when there are no items, this will be true and will add extra classe
89
+ # to the link to make the next and previous pagination links level
90
+ # @param govuk_pagination_next_options [Hash] options that will be used in customising the HTML
91
+ #
92
+ # @option govuk_pagination_next_options [String] :href the URL for the link
93
+ # @option govuk_pagination_next_options [String] :text ('Next') the text for the link
94
+ # @option govuk_pagination_next_options [String] :lable_text additional text for the link when the pagination block is level
95
+ # @option govuk_pagination_next_options [Hash] :attributes ({}) any additional attributes that will added as part of the HTML
96
+ #
97
+ # @return [ActiveSupport::SafeBuffer] the HTML for the next link which is used in {govuk_pagination}
98
+
99
+ def govuk_pagination_next(block_is_level, **govuk_pagination_next_options)
100
+ govuk_pagination_next_classes = ['govuk-pagination__link-title']
101
+ govuk_pagination_next_classes << 'govuk-pagination__link-title--decorated' if block_is_level && !govuk_pagination_next_options[:lable_text]
102
+
103
+ tag.div(class: 'govuk-pagination__next') do
104
+ link_to(govuk_pagination_next_options[:href], class: 'govuk-link govuk-pagination__link', rel: 'next', **(govuk_pagination_next_options[:attributes] || {})) do
105
+ capture do
106
+ concat(govuk_pagination_icon(:next)) if block_is_level
107
+ concat(tag.span(govuk_pagination_next_options[:text] || 'Next', class: govuk_pagination_next_classes))
108
+ concat(govuk_pagination_icon_label_text(block_is_level, govuk_pagination_next_options[:lable_text]))
109
+ concat(govuk_pagination_icon(:next)) unless block_is_level
110
+ end
111
+ end
112
+ end
113
+ end
114
+
115
+ # Generates the item links for {govuk_pagination}
116
+ #
117
+ # @param govuk_pagination_items [Array(Hash)] an array of item hashes for the pagination.
118
+ # There are two types of item:
119
+ # - {govuk_pagination_item_ellipsis ellipsis item}
120
+ # - {govuk_pagination_item_number number item}
121
+ #
122
+ # @return [ActiveSupport::SafeBuffer] the HTML for the lits of items which is used in {govuk_pagination}
123
+
124
+ def govuk_pagination_items(govuk_pagination_items)
125
+ tag.ul(class: 'govuk-pagination__list') do
126
+ capture do
127
+ govuk_pagination_items.each do |govuk_pagination_item|
128
+ case govuk_pagination_item[:type]
129
+ when :ellipsis
130
+ concat(govuk_pagination_item_ellipsis)
131
+ when :number
132
+ concat(govuk_pagination_item_number(govuk_pagination_item))
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+
139
+ # Generates the icon for:
140
+ # - {govuk_pagination_previous}
141
+ # - {govuk_pagination_next}
142
+ #
143
+ # @param type [Symbol] the type of the pagination icon (+:prev+ or +:next+)
144
+ #
145
+ # @return [ActiveSupport::SafeBuffer]
146
+
147
+ def govuk_pagination_icon(type)
148
+ tag.svg(class: "govuk-pagination__icon govuk-pagination__icon--#{type}", xmlns: 'http://www.w3.org/2000/svg', height: '13', width: '15', aria: { hidden: 'true' }, focusable: 'false', viewBox: '0 0 15 13') do
149
+ tag.path(d: PAGINATION_ICON_PATHS[type])
150
+ end
151
+ end
152
+
153
+ # Generates the label text for:
154
+ # - {govuk_pagination_previous}
155
+ # - {govuk_pagination_next}
156
+ #
157
+ # @param block_is_level [Boolean] when there are no items, this will be true
158
+ # @param label_text [String] the additional text for the link
159
+ #
160
+ # @return [ActiveSupport::SafeBuffer]
161
+
162
+ def govuk_pagination_icon_label_text(block_is_level, label_text)
163
+ return unless block_is_level && label_text
164
+
165
+ capture do
166
+ concat(tag.span(':', class: 'govuk-visually-hidden'))
167
+ concat(tag.span(label_text, class: 'govuk-pagination__link-label'))
168
+ end
169
+ end
170
+
171
+ # Generates the ellipsis HTML for {govuk_pagination_items}
172
+ #
173
+ # @return [ActiveSupport::SafeBuffer] the HTML for an ellipsis item which is used in {govuk_pagination_items}
174
+
175
+ def govuk_pagination_item_ellipsis
176
+ tag.li('⋯', class: 'govuk-pagination__item govuk-pagination__item--ellipses')
177
+ end
178
+
179
+ # Generates the number item HTML for {govuk_pagination_items}
180
+ #
181
+ # @param govuk_pagination_item [Hash] options that will be used in customising the HTML
182
+ #
183
+ # @option govuk_pagination_item [String] :href the URL for the link
184
+ # @option govuk_pagination_item [String] :number the number for the link
185
+ # @option govuk_pagination_item [String] :current is this item the current page
186
+ # @option govuk_pagination_item [Hash] :attributes ({aria: { label: 'Page <NUMBER>' } })
187
+ # any additional attributes that will added as part of the HTML
188
+ #
189
+ # @return [ActiveSupport::SafeBuffer] the HTML for an number item which is used in {govuk_pagination_items}
190
+
191
+ def govuk_pagination_item_number(govuk_pagination_item)
192
+ govuk_pagination_item_classes = ['govuk-pagination__item']
193
+ (govuk_pagination_item[:attributes] ||= {})[:aria] ||= {}
194
+ govuk_pagination_item[:attributes][:aria][:label] ||= "Page #{govuk_pagination_item[:number]}"
195
+
196
+ if govuk_pagination_item[:current]
197
+ govuk_pagination_item_classes << 'govuk-pagination__item--current'
198
+ govuk_pagination_item[:attributes][:aria][:current] = 'page'
199
+ end
200
+
201
+ tag.li(class: govuk_pagination_item_classes) do
202
+ link_to(govuk_pagination_item[:href], govuk_pagination_item[:number], class: 'govuk-link govuk-pagination__link', **govuk_pagination_item[:attributes])
203
+ end
204
+ end
205
+
206
+ # The paths for the pagination next and previous icons
207
+
208
+ PAGINATION_ICON_PATHS = {
209
+ prev: 'm6.5938-0.0078125-6.7266 6.7266 6.7441 6.4062 1.377-1.449-4.1856-3.9768h12.896v-2h-12.984l4.2931-4.293-1.414-1.414z',
210
+ next: 'm8.107-0.0078125-1.4136 1.414 4.2926 4.293h-12.986v2h12.896l-4.1855 3.9766 1.377 1.4492 6.7441-6.4062-6.7246-6.7266z'
211
+ }.freeze
212
+ end
213
+ end
214
+ end
@@ -0,0 +1,225 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'action_view'
4
+
5
+ module CrownMarketplaceUtils
6
+ module GovUkHelper
7
+ # = GOV.UK Step by step navigation
8
+ #
9
+ # This helper is used for generating the Step by step navigation component from the
10
+ # {https://design-system.service.gov.uk/patterns/step-by-step-navigation/ GDS - Pages - Step by step navigation}
11
+ #
12
+ # To use this component you need the following from {https://github.com/alphagov/govuk_publishing_components GOV.UK Publishing Components}.
13
+ # For the SCSS components you should add:
14
+ # - {https://github.com/alphagov/govuk_publishing_components/blob/main/app/assets/stylesheets/govuk_publishing_components/components/_step-by-step-nav.scss _step-by-step-nav.scss}
15
+ # - {https://github.com/alphagov/govuk_publishing_components/blob/main/app/assets/stylesheets/govuk_publishing_components/components/_step-by-step-nav-related.scss _step-by-step-nav-related.scss}
16
+ # - {https://github.com/alphagov/govuk_publishing_components/blob/main/app/assets/stylesheets/govuk_publishing_components/components/_step-by-step-nav-header.scss _step-by-step-nav-header.scss}
17
+ # For the JavaScript you should add:
18
+ # - {https://github.com/alphagov/govuk_publishing_components/blob/main/app/assets/javascripts/govuk_publishing_components/components/step-by-step-nav.js step-by-step-nav.js}
19
+
20
+ module StepByStepNavigation
21
+ include ActionView::Helpers
22
+ include ActionView::Context
23
+
24
+ # Generates the HTML for the GOV.UK Step by step navigation component (experimental)
25
+ #
26
+ # @param step_by_step_sections [Array] the navigation items that will be rendered to the page.
27
+ # See {govuk_step_by_step_navigation_section} for more details
28
+ # @param govuk_step_by_step_navigation_options [Hash] options that will be used in customising the HTML
29
+ #
30
+ # @option govuk_step_by_step_navigation_options [String] :classes additional CSS classes for the step by step navigation HTML
31
+ # @option govuk_step_by_step_navigation_options [Hash] :attributes ({data: { module: 'govuk-step-by-step-navigation', 'show-text': 'Show', 'hide-text': 'Hide', 'show-all-text': 'Show all', 'hide-all-text': 'Hide all' } })
32
+ # any additional attributes that will added as part of the HTML
33
+ #
34
+ # @return [ActiveSupport::SafeBuffer] the HTML for the GOV.UK Step by step navigation
35
+ # which can then be rendered on the page
36
+
37
+ def govuk_step_by_step_navigation(step_by_step_sections, **govuk_step_by_step_navigation_options)
38
+ govuk_step_by_step_navigation_classes = ['gem-c-step-nav gem-c-step-nav--large gem-c-step-nav--active']
39
+ govuk_step_by_step_navigation_classes << govuk_step_by_step_navigation_options[:classes]
40
+
41
+ tag.div(class: govuk_step_by_step_navigation_classes, **govuk_step_by_step_navigation_attributes(**govuk_step_by_step_navigation_options)) do
42
+ tag.ol(class: 'gem-c-step-nav__steps') do
43
+ capture do
44
+ step_by_step_sections.each.with_index(1) { |step_by_step_section, section_index| concat(govuk_step_by_step_navigation_section(step_by_step_section, section_index.to_s)) }
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ # The HTML for a section within GOV.UK Step by step navigation, used by {govuk_step_by_step_navigation}
53
+ #
54
+ # @param step_by_step_section [Hash] the parameters that will be used to create the section
55
+ # @param section_index [String] the index of the section
56
+ #
57
+ # @option step_by_step_section [Hash] :heading the paramaters for the section heading,
58
+ # see {govuk_step_by_step_navigation_heading} for more details
59
+ # @option step_by_step_section [Array] :content the paramaters for the section content,
60
+ # see {govuk_step_by_step_navigation_content} for more details
61
+ #
62
+ # @return [ActiveSupport::SafeBuffer] the HTML for the GOV.UK Step by step navigation section
63
+ # which is used in {govuk_step_by_step_navigation}
64
+
65
+ def govuk_step_by_step_navigation_section(step_by_step_section, section_index)
66
+ section_id = convert_to_id(step_by_step_section[:heading][:text])
67
+
68
+ tag.li(class: 'gem-c-step-nav__step js-step', id: section_id) do
69
+ capture do
70
+ concat(govuk_step_by_step_navigation_heading(step_by_step_section[:heading], section_index))
71
+ concat(govuk_step_by_step_navigation_content(step_by_step_section[:content], section_id, section_index))
72
+ end
73
+ end
74
+ end
75
+
76
+ # The HTML for a section heading within GOV.UK Step by step navigation, used by {govuk_step_by_step_navigation_section}
77
+ #
78
+ # @param section_heading [Hash] the parameters that will be used to create the heading
79
+ # @param section_index [String] the index of the section
80
+ #
81
+ # @option section_heading [Hash] :text text for the section heading
82
+ # @option section_heading [Hash] :logic (nil) text to show instead of a number in the sidebar
83
+ #
84
+ # @return [ActiveSupport::SafeBuffer] the HTML for the GOV.UK Step by step navigation section heading
85
+ # which is used in {govuk_step_by_step_navigation_section}
86
+
87
+ def govuk_step_by_step_navigation_heading(section_heading, section_index)
88
+ logic = section_heading[:logic]
89
+
90
+ tag.div(class: 'gem-c-step-nav__header js-toggle-panel', data: { position: section_index }) do
91
+ tag.h2(class: 'gem-c-step-nav__title') do
92
+ capture do
93
+ concat(tag.span(class: "gem-c-step-nav__circle gem-c-step-nav__circle--#{logic ? 'logic' : 'number'}") do
94
+ tag.span(class: 'gem-c-step-nav__circle-inner') do
95
+ tag.span(class: 'gem-c-step-nav__circle-background') do
96
+ capture do
97
+ concat(tag.span('Step', class: 'govuk-visually-hidden'))
98
+ concat(logic || section_index)
99
+ end
100
+ end
101
+ end
102
+ end)
103
+ concat(tag.span(class: 'js-step-title') do
104
+ tag.span(section_heading[:text], class: 'js-step-title-text')
105
+ end)
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ # The HTML for a section content within GOV.UK Step by step navigation, used by {govuk_step_by_step_navigation_section}
112
+ #
113
+ # @param content [Array] an array of the content items that will be rendered within the section.
114
+ # Only two types of content are allowed:
115
+ # - +:paragraph+ - see {govuk_step_by_step_navigation_paragraph}
116
+ # - +:list+ - see {govuk_step_by_step_navigation_list}
117
+ # @param section_id [String] the id of the section
118
+ # @param section_index [String] the index of the section
119
+ #
120
+ # @option content [Symbol] :type the type of content, either +:paragraph+ or +list+
121
+ # @option content [Symbol] :text the text for the paragraph. Ignored unless the +type+ is +:list+
122
+ # @option content [Symbol] :items the items for the list. Ignored unless the +type+ is +:paragraph+
123
+ #
124
+ # @return [ActiveSupport::SafeBuffer] the HTML for the GOV.UK Step by step navigation section content
125
+ # which is used in {govuk_step_by_step_navigation_section}
126
+
127
+ def govuk_step_by_step_navigation_content(content, section_id, section_index)
128
+ tag.div(class: 'gem-c-step-nav__panel js-panel', id: "step-panel-#{section_id}-#{section_index}") do
129
+ capture do
130
+ content.each do |element|
131
+ concat(
132
+ case element[:type]
133
+ when :paragraph
134
+ govuk_step_by_step_navigation_paragraph(element[:text])
135
+ when :list
136
+ govuk_step_by_step_navigation_list(element[:items])
137
+ end
138
+ )
139
+ end
140
+ end
141
+ end
142
+ end
143
+
144
+ # The HTML for the paragraph item within the GOV.UK Step by step navigation content, used by {govuk_step_by_step_navigation_content}
145
+ #
146
+ # @param text [String] the text for the paragraph
147
+ #
148
+ # @return [ActiveSupport::SafeBuffer] the HTML for the paragraph
149
+ # which is used in {govuk_step_by_step_navigation_content}
150
+
151
+ def govuk_step_by_step_navigation_paragraph(text)
152
+ tag.p(
153
+ text,
154
+ class: 'gem-c-step-nav__paragraph',
155
+ )
156
+ end
157
+
158
+ # The HTML for the list items within the GOV.UK Step by step navigation content, used by {govuk_step_by_step_navigation_content}
159
+ #
160
+ # @param items [Array] an array of the list items,
161
+ # see {govuk_step_by_step_navigation_list_item} for more details
162
+ #
163
+ # @return [ActiveSupport::SafeBuffer] the HTML for the list
164
+ # which is used in {govuk_step_by_step_navigation_content}
165
+
166
+ def govuk_step_by_step_navigation_list(items)
167
+ tag.ul(class: 'gem-c-step-nav__list gem-c-step-nav__list--choice', data: { length: items.length.to_s }) do
168
+ capture do
169
+ items.each do |item|
170
+ concat(govuk_step_by_step_navigation_list_item(item[:text], item[:no_marker]))
171
+ end
172
+ end
173
+ end
174
+ end
175
+
176
+ # The HTML for a list item, used by {govuk_step_by_step_navigation_list}
177
+ #
178
+ # @param text [Symbol] the text of the list item
179
+ # @param no_marker [Symbol] (nil) switch to hide the bullet marker
180
+ #
181
+ # @return [ActiveSupport::SafeBuffer] the HTML for the list item
182
+ # which is used in {govuk_step_by_step_navigation_list}
183
+
184
+ def govuk_step_by_step_navigation_list_item(text, no_marker)
185
+ list_item_classes = ['gem-c-step-nav__list-item js-list-item']
186
+ list_item_classes << 'gem-c-step-nav__list--no-marker' if no_marker
187
+
188
+ tag.li(class: list_item_classes) do
189
+ tag.span(text)
190
+ end
191
+ end
192
+
193
+ # Converts the title text into a string to be used as the section id
194
+ #
195
+ # @param title [String] the section title that will be converted
196
+ #
197
+ # @return [String] the section id
198
+
199
+ def convert_to_id(title)
200
+ title.downcase.gsub(' ', '-').gsub('(', '').gsub(')', '')
201
+ end
202
+
203
+ # Generates a hash with the attributes used in {govuk_step_by_step_navigation}
204
+ #
205
+ # @param govuk_step_by_step_navigation_options [Hash] options that will be used in customising the HTML
206
+ #
207
+ # @option (see govuk_step_by_step_navigation)
208
+ #
209
+ # @return [Hash] contains the HTMl attributes used in {govuk_step_by_step_navigation}
210
+
211
+ def govuk_step_by_step_navigation_attributes(**govuk_step_by_step_navigation_options)
212
+ govuk_step_by_step_navigation_options[:attributes] ||= {}
213
+ (govuk_step_by_step_navigation_options[:attributes][:data] ||= {}).merge!({ module: 'govuk-step-by-step-navigation' })
214
+
215
+ DEFAULT_SHOW_HIDE_TEXT.each { |key, value| govuk_step_by_step_navigation_options[:attributes][:data][key] ||= value }
216
+
217
+ govuk_step_by_step_navigation_options[:attributes]
218
+ end
219
+
220
+ # Default text for the show and hide buttons which are part of each section
221
+
222
+ DEFAULT_SHOW_HIDE_TEXT = { 'show-text': 'Show', 'hide-text': 'Hide', 'show-all-text': 'Show all', 'hide-all-text': 'Hide all' }.freeze
223
+ end
224
+ end
225
+ end