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

Sign up to get free protection for your applications and to get access to all the features.
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