govuk_design_system_formbuilder 1.2.3 → 2.0.0b1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/lib/govuk_design_system_formbuilder.rb +1 -1
  4. data/lib/govuk_design_system_formbuilder/base.rb +1 -1
  5. data/lib/govuk_design_system_formbuilder/builder.rb +155 -60
  6. data/lib/govuk_design_system_formbuilder/containers/character_count.rb +8 -7
  7. data/lib/govuk_design_system_formbuilder/containers/check_boxes.rb +18 -10
  8. data/lib/govuk_design_system_formbuilder/containers/check_boxes_fieldset.rb +13 -4
  9. data/lib/govuk_design_system_formbuilder/containers/fieldset.rb +15 -55
  10. data/lib/govuk_design_system_formbuilder/containers/form_group.rb +19 -10
  11. data/lib/govuk_design_system_formbuilder/containers/radio_buttons_fieldset.rb +13 -4
  12. data/lib/govuk_design_system_formbuilder/containers/radios.rb +22 -11
  13. data/lib/govuk_design_system_formbuilder/containers/supplemental.rb +3 -3
  14. data/lib/govuk_design_system_formbuilder/elements/caption.rb +6 -4
  15. data/lib/govuk_design_system_formbuilder/elements/check_boxes/collection.rb +21 -12
  16. data/lib/govuk_design_system_formbuilder/elements/check_boxes/collection_check_box.rb +9 -7
  17. data/lib/govuk_design_system_formbuilder/elements/check_boxes/fieldset_check_box.rb +24 -16
  18. data/lib/govuk_design_system_formbuilder/elements/date.rb +47 -40
  19. data/lib/govuk_design_system_formbuilder/elements/error_message.rb +4 -4
  20. data/lib/govuk_design_system_formbuilder/elements/error_summary.rb +15 -15
  21. data/lib/govuk_design_system_formbuilder/elements/file.rb +8 -7
  22. data/lib/govuk_design_system_formbuilder/elements/hint.rb +43 -16
  23. data/lib/govuk_design_system_formbuilder/elements/inputs/email.rb +2 -2
  24. data/lib/govuk_design_system_formbuilder/elements/inputs/number.rb +0 -2
  25. data/lib/govuk_design_system_formbuilder/elements/inputs/password.rb +0 -2
  26. data/lib/govuk_design_system_formbuilder/elements/inputs/phone.rb +0 -2
  27. data/lib/govuk_design_system_formbuilder/elements/inputs/text.rb +0 -2
  28. data/lib/govuk_design_system_formbuilder/elements/inputs/url.rb +0 -2
  29. data/lib/govuk_design_system_formbuilder/elements/label.rb +35 -27
  30. data/lib/govuk_design_system_formbuilder/elements/legend.rb +79 -0
  31. data/lib/govuk_design_system_formbuilder/elements/radios/collection.rb +23 -14
  32. data/lib/govuk_design_system_formbuilder/elements/radios/collection_radio_button.rb +24 -8
  33. data/lib/govuk_design_system_formbuilder/elements/radios/fieldset_radio_button.rb +19 -7
  34. data/lib/govuk_design_system_formbuilder/elements/select.rb +24 -19
  35. data/lib/govuk_design_system_formbuilder/elements/submit.rb +11 -6
  36. data/lib/govuk_design_system_formbuilder/elements/text_area.rb +31 -25
  37. data/lib/govuk_design_system_formbuilder/traits/collection_item.rb +1 -1
  38. data/lib/govuk_design_system_formbuilder/traits/conditional.rb +1 -1
  39. data/lib/govuk_design_system_formbuilder/traits/hint.rb +15 -2
  40. data/lib/govuk_design_system_formbuilder/traits/input.rb +9 -8
  41. data/lib/govuk_design_system_formbuilder/traits/label.rb +2 -2
  42. data/lib/govuk_design_system_formbuilder/version.rb +1 -1
  43. metadata +11 -10
@@ -8,12 +8,12 @@ module GOVUKDesignSystemFormBuilder
8
8
  include Traits::Hint
9
9
  include Traits::Conditional
10
10
 
11
- def initialize(builder, object_name, attribute_name, value, label:, hint_text:, link_errors:, multiple:, &block)
11
+ def initialize(builder, object_name, attribute_name, value, label:, hint:, link_errors:, multiple:, &block)
12
12
  super(builder, object_name, attribute_name)
13
13
 
14
14
  @value = value
15
15
  @label = label
16
- @hint_text = hint_text
16
+ @hint = hint
17
17
  @multiple = multiple
18
18
  @link_errors = link_errors
19
19
 
@@ -24,45 +24,53 @@ module GOVUKDesignSystemFormBuilder
24
24
  end
25
25
 
26
26
  def html
27
- safe_join([check_box, @conditional_content])
27
+ safe_join([item, @conditional_content])
28
28
  end
29
29
 
30
30
  private
31
31
 
32
- def check_box
33
- content_tag('div', class: %(#{brand}-checkboxes__item)) do
34
- safe_join([input, label_element, hint_element])
32
+ def item
33
+ tag.div(class: %(#{brand}-checkboxes__item)) do
34
+ safe_join([check_box, label_element, hint_element])
35
35
  end
36
36
  end
37
37
 
38
- def input
39
- @builder.check_box(@attribute_name, input_options, @value, false)
38
+ def check_box
39
+ @builder.check_box(@attribute_name, options, @value, false)
40
40
  end
41
41
 
42
- def input_options
42
+ def options
43
43
  {
44
44
  id: field_id(link_errors: @link_errors),
45
- class: check_box_classes,
45
+ class: classes,
46
46
  multiple: @multiple,
47
47
  aria: { describedby: hint_id },
48
48
  data: { 'aria-controls' => @conditional_id }
49
49
  }
50
50
  end
51
51
 
52
+ def classes
53
+ %w(checkboxes__input).prefix(brand)
54
+ end
55
+
52
56
  def label_element
53
- @label_element ||= Elements::Label.new(@builder, @object_name, @attribute_name, checkbox: true, value: @value, link_errors: @link_errors, **label_options)
57
+ @label_element ||= Elements::Label.new(@builder, @object_name, @attribute_name, **label_content, **label_options)
58
+ end
59
+
60
+ def label_options
61
+ { checkbox: true, value: @value, link_errors: @link_errors }
54
62
  end
55
63
 
56
64
  def hint_element
57
- @hint_element ||= Elements::Hint.new(@builder, @object_name, @attribute_name, @hint_text, @value, checkbox: true)
65
+ @hint_element ||= Elements::Hint.new(@builder, @object_name, @attribute_name, **hint_options, **hint_content)
58
66
  end
59
67
 
60
- def conditional_classes
61
- %w(checkboxes__conditional checkboxes__conditional--hidden).prefix(brand)
68
+ def hint_options
69
+ { checkbox: true }
62
70
  end
63
71
 
64
- def check_box_classes
65
- %w(checkboxes__input).prefix(brand)
72
+ def conditional_classes
73
+ %w(checkboxes__conditional checkboxes__conditional--hidden).prefix(brand)
66
74
  end
67
75
  end
68
76
  end
@@ -9,19 +9,20 @@ module GOVUKDesignSystemFormBuilder
9
9
 
10
10
  SEGMENTS = { day: '3i', month: '2i', year: '1i' }.freeze
11
11
 
12
- def initialize(builder, object_name, attribute_name, legend:, caption:, hint_text:, date_of_birth: false, omit_day:, &block)
12
+ def initialize(builder, object_name, attribute_name, legend:, caption:, hint:, date_of_birth: false, omit_day:, form_group:, &block)
13
13
  super(builder, object_name, attribute_name, &block)
14
14
 
15
15
  @legend = legend
16
16
  @caption = caption
17
- @hint_text = hint_text
17
+ @hint = hint
18
18
  @date_of_birth = date_of_birth
19
19
  @omit_day = omit_day
20
+ @form_group = form_group
20
21
  end
21
22
 
22
23
  def html
23
- Containers::FormGroup.new(@builder, @object_name, @attribute_name).html do
24
- Containers::Fieldset.new(@builder, @object_name, @attribute_name, legend: @legend, caption: @caption, described_by: [error_id, hint_id, supplemental_id]).html do
24
+ Containers::FormGroup.new(@builder, @object_name, @attribute_name, **@form_group).html do
25
+ Containers::Fieldset.new(@builder, @object_name, @attribute_name, **fieldset_options).html do
25
26
  safe_join([supplemental_content, hint_element, error_element, date])
26
27
  end
27
28
  end
@@ -29,8 +30,12 @@ module GOVUKDesignSystemFormBuilder
29
30
 
30
31
  private
31
32
 
33
+ def fieldset_options
34
+ { legend: @legend, caption: @caption, described_by: [error_id, hint_id, supplemental_id] }
35
+ end
36
+
32
37
  def date
33
- content_tag('div', class: %(#{brand}-date-input)) do
38
+ tag.div(class: %(#{brand}-date-input)) do
34
39
  safe_join([day, month, year])
35
40
  end
36
41
  end
@@ -42,61 +47,59 @@ module GOVUKDesignSystemFormBuilder
42
47
  def day
43
48
  return nil if omit_day?
44
49
 
45
- date_part_input(:day, link_errors: true)
50
+ date_part(:day, width: 2, link_errors: true)
46
51
  end
47
52
 
48
53
  def month
49
- date_part_input(:month, link_errors: omit_day?)
54
+ date_part(:month, width: 2, link_errors: omit_day?)
50
55
  end
51
56
 
52
57
  def year
53
- date_part_input(:year, width: 4)
58
+ date_part(:year, width: 4)
54
59
  end
55
60
 
56
- def date_part_input(segment, width: 2, link_errors: false)
61
+ def date_part(segment, width:, link_errors: false)
57
62
  value = @builder.object.try(@attribute_name).try(segment)
58
63
 
59
- content_tag('div', class: %w(date-input__item).prefix(brand)) do
60
- content_tag('div', class: %w(form-group).prefix(brand)) do
61
- safe_join(
62
- [
63
- tag.label(
64
- segment.capitalize,
65
- class: date_part_label_classes,
66
- for: date_part_attribute_id(segment, link_errors)
67
- ),
68
-
69
- tag.input(
70
- id: date_part_attribute_id(segment, link_errors),
71
- class: date_part_input_classes(width),
72
- name: date_part_attribute_name(segment),
73
- type: 'text',
74
- pattern: '[0-9]*',
75
- inputmode: 'numeric',
76
- value: value,
77
- autocomplete: date_of_birth_autocomplete_value(segment)
78
- )
79
- ]
80
- )
64
+ tag.div(class: %(#{brand}-date-input__item)) do
65
+ tag.div(class: %(#{brand}-form-group)) do
66
+ safe_join([label(segment, link_errors), input(segment, link_errors, width, value)])
81
67
  end
82
68
  end
83
69
  end
84
70
 
85
- def date_part_input_classes(width)
71
+ def label(segment, link_errors)
72
+ tag.label(
73
+ segment.capitalize,
74
+ class: label_classes,
75
+ for: id(segment, link_errors)
76
+ )
77
+ end
78
+
79
+ def input(segment, link_errors, width, value)
80
+ tag.input(
81
+ id: id(segment, link_errors),
82
+ class: classes(width),
83
+ name: name(segment),
84
+ type: 'text',
85
+ pattern: '[0-9]*',
86
+ inputmode: 'numeric',
87
+ value: value,
88
+ autocomplete: date_of_birth_autocomplete_value(segment)
89
+ )
90
+ end
91
+
92
+ def classes(width)
86
93
  %w(input date-input__input).prefix(brand).tap do |classes|
87
94
  classes.push(%(#{brand}-input--width-#{width}))
88
95
  classes.push(%(#{brand}-input--error)) if has_errors?
89
96
  end
90
97
  end
91
98
 
92
- def date_part_label_classes
93
- %w(label date-input__label).prefix(brand)
94
- end
95
-
96
99
  # if the field has errors we want the govuk_error_summary to
97
100
  # be able to link to the day field. Otherwise, generate IDs
98
101
  # in the normal fashion
99
- def date_part_attribute_id(segment, link_errors)
102
+ def id(segment, link_errors)
100
103
  if has_errors? && link_errors
101
104
  field_id(link_errors: link_errors)
102
105
  else
@@ -104,11 +107,11 @@ module GOVUKDesignSystemFormBuilder
104
107
  end
105
108
  end
106
109
 
107
- def date_part_attribute_name(segment)
110
+ def name(segment)
108
111
  format(
109
- "%<object_name>s[%<attribute_name>s(%<segment>s)]",
112
+ "%<object_name>s[%<input_name>s(%<segment>s)]",
110
113
  object_name: @object_name,
111
- attribute_name: @attribute_name,
114
+ input_name: @attribute_name,
112
115
  segment: SEGMENTS.fetch(segment)
113
116
  )
114
117
  end
@@ -118,6 +121,10 @@ module GOVUKDesignSystemFormBuilder
118
121
 
119
122
  { day: 'bday-day', month: 'bday-month', year: 'bday-year' }.fetch(segment)
120
123
  end
124
+
125
+ def label_classes
126
+ %w(label date-input__label).prefix(brand)
127
+ end
121
128
  end
122
129
  end
123
130
  end
@@ -12,18 +12,18 @@ module GOVUKDesignSystemFormBuilder
12
12
  def html
13
13
  return nil unless has_errors?
14
14
 
15
- content_tag('span', class: %(#{brand}-error-message), id: error_id) do
16
- safe_join([error_prefix, error_message])
15
+ tag.span(class: %(#{brand}-error-message), id: error_id) do
16
+ safe_join([hidden_prefix, message])
17
17
  end
18
18
  end
19
19
 
20
20
  private
21
21
 
22
- def error_prefix
22
+ def hidden_prefix
23
23
  tag.span('Error: ', class: %(#{brand}-visually-hidden))
24
24
  end
25
25
 
26
- def error_message
26
+ def message
27
27
  @builder.object.errors.messages[@attribute_name]&.first
28
28
  end
29
29
  end
@@ -12,32 +12,32 @@ module GOVUKDesignSystemFormBuilder
12
12
  def html
13
13
  return nil unless object_has_errors?
14
14
 
15
- content_tag('div', class: error_summary_class, **error_summary_options) do
16
- safe_join([error_title, error_summary])
15
+ tag.div(class: summary_class, **summary_options) do
16
+ safe_join([title, summary])
17
17
  end
18
18
  end
19
19
 
20
20
  private
21
21
 
22
- def error_title
23
- tag.h2(@title, id: error_summary_title_id, class: error_summary_class('title'))
22
+ def title
23
+ tag.h2(@title, id: summary_title_id, class: summary_class('title'))
24
24
  end
25
25
 
26
- def error_summary
27
- content_tag('div', class: error_summary_class('body')) do
28
- content_tag('ul', class: [%(#{brand}-list), error_summary_class('list')]) do
29
- safe_join(error_list)
26
+ def summary
27
+ tag.div(class: summary_class('body')) do
28
+ tag.ul(class: [%(#{brand}-list), summary_class('list')]) do
29
+ safe_join(list)
30
30
  end
31
31
  end
32
32
  end
33
33
 
34
- def error_list
34
+ def list
35
35
  @builder.object.errors.messages.map do |attribute, messages|
36
- error_list_item(attribute, messages.first)
36
+ list_item(attribute, messages.first)
37
37
  end
38
38
  end
39
39
 
40
- def error_list_item(attribute, message)
40
+ def list_item(attribute, message)
41
41
  tag.li(link_to(message, same_page_link(field_id(attribute)), data: { turbolinks: false }))
42
42
  end
43
43
 
@@ -45,7 +45,7 @@ module GOVUKDesignSystemFormBuilder
45
45
  '#'.concat(target)
46
46
  end
47
47
 
48
- def error_summary_class(part = nil)
48
+ def summary_class(part = nil)
49
49
  if part
50
50
  %(#{brand}-error-summary).concat('__', part)
51
51
  else
@@ -57,7 +57,7 @@ module GOVUKDesignSystemFormBuilder
57
57
  build_id('field-error', attribute_name: attribute)
58
58
  end
59
59
 
60
- def error_summary_title_id
60
+ def summary_title_id
61
61
  'error-summary-title'
62
62
  end
63
63
 
@@ -65,7 +65,7 @@ module GOVUKDesignSystemFormBuilder
65
65
  @builder.object.errors.any?
66
66
  end
67
67
 
68
- def error_summary_options
68
+ def summary_options
69
69
  {
70
70
  tabindex: -1,
71
71
  role: 'alert',
@@ -73,7 +73,7 @@ module GOVUKDesignSystemFormBuilder
73
73
  module: %(#{brand}-error-summary)
74
74
  },
75
75
  aria: {
76
- labelledby: error_summary_title_id
76
+ labelledby: summary_title_id
77
77
  }
78
78
  }
79
79
  end
@@ -8,17 +8,18 @@ module GOVUKDesignSystemFormBuilder
8
8
  include Traits::Label
9
9
  include Traits::Supplemental
10
10
 
11
- def initialize(builder, object_name, attribute_name, hint_text:, label:, caption:, **kwargs, &block)
11
+ def initialize(builder, object_name, attribute_name, hint:, label:, caption:, form_group:, **kwargs, &block)
12
12
  super(builder, object_name, attribute_name, &block)
13
13
 
14
14
  @label = label
15
15
  @caption = caption
16
- @hint_text = hint_text
16
+ @hint = hint
17
17
  @extra_options = kwargs
18
+ @form_group = form_group
18
19
  end
19
20
 
20
21
  def html
21
- Containers::FormGroup.new(@builder, @object_name, @attribute_name).html do
22
+ Containers::FormGroup.new(@builder, @object_name, @attribute_name, **@form_group).html do
22
23
  safe_join([label_element, supplemental_content, hint_element, error_element, file])
23
24
  end
24
25
  end
@@ -26,18 +27,18 @@ module GOVUKDesignSystemFormBuilder
26
27
  private
27
28
 
28
29
  def file
29
- @builder.file_field(@attribute_name, **file_options, **@extra_options)
30
+ @builder.file_field(@attribute_name, **options, **@extra_options)
30
31
  end
31
32
 
32
- def file_options
33
+ def options
33
34
  {
34
35
  id: field_id(link_errors: true),
35
- class: file_classes,
36
+ class: classes,
36
37
  aria: { describedby: described_by(hint_id, error_id, supplemental_id) }
37
38
  }
38
39
  end
39
40
 
40
- def file_classes
41
+ def classes
41
42
  %w(file-upload).prefix(brand).tap do |c|
42
43
  c.push(%(#{brand}-file-upload--error)) if has_errors?
43
44
  end
@@ -3,40 +3,67 @@ module GOVUKDesignSystemFormBuilder
3
3
  class Hint < Base
4
4
  using PrefixableArray
5
5
 
6
- include Traits::Hint
7
6
  include Traits::Localisation
8
7
 
9
- def initialize(builder, object_name, attribute_name, text, value = nil, radio: false, checkbox: false)
8
+ def initialize(builder, object_name, attribute_name, value: nil, text: nil, content: nil, radio: false, checkbox: false, **kwargs)
10
9
  super(builder, object_name, attribute_name)
11
10
 
12
- @value = value
13
- @hint_text = hint_text(text)
14
- @radio_class = radio_class(radio)
15
- @checkbox_class = checkbox_class(checkbox)
11
+ @radio = radio
12
+ @checkbox = checkbox
13
+ @html_attributes = kwargs
14
+
15
+ if content
16
+ @content = capture { content.call }
17
+ else
18
+ @text = retrieve_text(text)
19
+ @value = value
20
+ end
21
+ end
22
+
23
+ def active?
24
+ [@text, @content].any?(&:present?)
16
25
  end
17
26
 
18
27
  def html
19
- return nil if @hint_text.blank?
28
+ return nil unless active?
29
+
30
+ content_tag(hint_tag, **hint_options, **@html_attributes) { hint_body }
31
+ end
32
+
33
+ def hint_id
34
+ return nil unless active?
20
35
 
21
- tag.span(@hint_text, class: hint_classes, id: hint_id)
36
+ build_id('hint')
22
37
  end
23
38
 
24
39
  private
25
40
 
26
- def hint_text(supplied)
27
- [supplied.presence, localised_text(:hint)].compact.first
41
+ def hint_options
42
+ { class: classes, id: hint_id }
43
+ end
44
+
45
+ def hint_tag
46
+ @content.presence ? 'div' : 'span'
47
+ end
48
+
49
+ def hint_body
50
+ @content || @text
51
+ end
52
+
53
+ def retrieve_text(supplied)
54
+ supplied.presence || localised_text(:hint)
28
55
  end
29
56
 
30
- def hint_classes
31
- %w(hint).prefix(brand).push(@radio_class, @checkbox_class).compact
57
+ def classes
58
+ %w(hint).prefix(brand).push(radio_class, checkbox_class).compact
32
59
  end
33
60
 
34
- def radio_class(radio)
35
- radio ? %(#{brand}-radios__hint) : nil
61
+ def radio_class
62
+ @radio ? %(#{brand}-radios__hint) : nil
36
63
  end
37
64
 
38
- def checkbox_class(checkbox)
39
- checkbox ? %(#{brand}-checkboxes__hint) : nil
65
+ def checkbox_class
66
+ @checkbox ? %(#{brand}-checkboxes__hint) : nil
40
67
  end
41
68
  end
42
69
  end