govuk_design_system_formbuilder 2.5.0 → 2.6.0b1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bad17ea5b7fd24f59da43ac8e0348d27c07589bce648172278c7041e95c4a702
4
- data.tar.gz: e8dee08e15dfe0dc4a34de248ef8a2991e789a74ea3452324bbcad81e0ec6612
3
+ metadata.gz: 434236656800572e0d71e47fe88ae20e5f50c6822f3cf344204f08a934032cb9
4
+ data.tar.gz: 4746012c475f169cf556fed6512ef89aa0187e95f351addc38b14da835db6137
5
5
  SHA512:
6
- metadata.gz: ea8519f8c72d431fa56feae8d98e21ff90117c58dcd1e91385ed41a4863299cd74b15f959dd4e4118e3281bccd8a048625013dcdc2dd00fa1d873479d5294f57
7
- data.tar.gz: 969f85302cc4c1e898664c04bf1d435d69ed0408fa0bf03890160803c0b6574eabeafc16418cfe8df353e718ff062f6600272d6bccbd596be4fe248c5295dfc5
6
+ metadata.gz: 6dae8d1bc5dec93e9088aa68f78df41fd06bd9a9815ee65919b14c7fcb96aeb27400390f83e122e540392b2254378c03d2e7455316f9e09d3c4694652e801ce1
7
+ data.tar.gz: 3f3a3a53125291c4822e2b557c3c6f0ed053e4127bf0b7561b5bc82ca5a1a14b601d01b591bf4dd6901979f3b0b55a018c52ecf74e769ef602ddaef05ea454d4
data/README.md CHANGED
@@ -7,9 +7,9 @@
7
7
  [![Test Coverage](https://api.codeclimate.com/v1/badges/fde73b5dc9476197281b/test_coverage)](https://codeclimate.com/github/DFE-Digital/govuk_design_system_formbuilder/test_coverage)
8
8
  [![Dependabot Status](https://api.dependabot.com/badges/status?host=github&repo=DFE-Digital/govuk_design_system_formbuilder)](https://dependabot.com)
9
9
  [![GitHub license](https://img.shields.io/github/license/DFE-Digital/govuk_design_system_formbuilder)](https://github.com/DFE-Digital/govuk_design_system_formbuilder/blob/master/LICENSE)
10
- [![GOV.UK Design System Version](https://img.shields.io/badge/GOV.UK%20Design%20System-3.11.0-brightgreen)](https://design-system.service.gov.uk)
10
+ [![GOV.UK Design System Version](https://img.shields.io/badge/GOV.UK%20Design%20System-3.12.0-brightgreen)](https://design-system.service.gov.uk)
11
11
  [![Rails](https://img.shields.io/badge/Ruby-2.6.7%20%E2%95%B1%202.7.3%20%E2%95%B1%203.0.1-E16D6D)](https://www.ruby-lang.org/en/downloads/)
12
- [![Ruby](https://img.shields.io/badge/Rails-6.0.3.6%20%E2%95%B1%206.1.3.1-E16D6D)](https://weblog.rubyonrails.org/releases/)
12
+ [![Ruby](https://img.shields.io/badge/Rails-6.0.3.7%20%E2%95%B1%206.1.3.2-E16D6D)](https://weblog.rubyonrails.org/releases/)
13
13
 
14
14
  This library provides an easy-to-use form builder for the [GOV.UK Design System](https://design-system.service.gov.uk/).
15
15
 
@@ -1,7 +1,7 @@
1
1
  require 'deep_merge/rails_compat'
2
2
  require 'active_support/configurable'
3
3
 
4
- [%w(traits *.rb), %w(*.rb), %w(elements ** *.rb), %w(containers ** *.rb)]
4
+ [%w(refinements *.rb), %w(traits *.rb), %w(*.rb), %w(elements ** *.rb), %w(containers ** *.rb)]
5
5
  .flat_map { |matcher| Dir.glob(File.join(__dir__, 'govuk_design_system_formbuilder', *matcher)) }
6
6
  .each { |file| require file }
7
7
 
@@ -108,6 +108,8 @@ module GOVUKDesignSystemFormBuilder
108
108
  include GOVUKDesignSystemFormBuilder::Builder
109
109
  end
110
110
 
111
+ class FormBuilderProxy < FormBuilder; end
112
+
111
113
  # Disable Rails' div.field_with_error wrapper
112
114
  ActionView::Base.field_error_proc = ->(html_tag, _instance) { html_tag }
113
115
  end
@@ -1,12 +1,4 @@
1
1
  module GOVUKDesignSystemFormBuilder
2
- module PrefixableArray
3
- refine Array do
4
- def prefix(text, delimiter: '-')
5
- map { |item| text + delimiter + item }
6
- end
7
- end
8
- end
9
-
10
2
  class Base
11
3
  delegate :content_tag, :safe_join, :tag, :link_to, :capture, to: :@builder
12
4
  delegate :config, to: GOVUKDesignSystemFormBuilder
@@ -23,21 +15,6 @@ module GOVUKDesignSystemFormBuilder
23
15
  html || ''
24
16
  end
25
17
 
26
- private
27
-
28
- # returns the attributes bound to the object that are
29
- # required to build all contained elements
30
- #
31
- # @return [GOVUKDesignSystemFormBuilder::FormBuilder, Symbol, Symbol] an array containing the
32
- # builder, object name and attribute name
33
- def bound
34
- [@builder, @object_name, @attribute_name]
35
- end
36
-
37
- def brand(override = nil)
38
- override || config.brand
39
- end
40
-
41
18
  # returns the id value used for the input
42
19
  #
43
20
  # @note field_id is overridden so that the error summary can link to the
@@ -59,6 +36,21 @@ module GOVUKDesignSystemFormBuilder
59
36
  end
60
37
  end
61
38
 
39
+ private
40
+
41
+ # returns the attributes bound to the object that are
42
+ # required to build all contained elements
43
+ #
44
+ # @return [GOVUKDesignSystemFormBuilder::FormBuilder, Symbol, Symbol] an array containing the
45
+ # builder, object name and attribute name
46
+ def bound
47
+ [@builder, @object_name, @attribute_name]
48
+ end
49
+
50
+ def brand(override = nil)
51
+ override || config.brand
52
+ end
53
+
62
54
  def has_errors?
63
55
  @builder.object.respond_to?(:errors) &&
64
56
  @builder.object.errors.any? &&
@@ -0,0 +1,65 @@
1
+ module GOVUKDesignSystemFormBuilder
2
+ # NOTE: this is currently considered experimental, it's likely to change based on feedback.
3
+ #
4
+ # BuilderHelper contains methods that expose the form builder's functionality
5
+ # externally. The objectives are to allow:
6
+ #
7
+ # * rendering the error summary outside of the form
8
+ #
9
+ # * setting the id of custom form elements (rich text editors, date pickers,
10
+ # sliders, etc) using the formbuilder's internal logic, allowing them to be
11
+ # linked from the error summary
12
+ module BuilderHelper
13
+ # Returns the form builder generated id for an object's attribute, allowing
14
+ # users to force their custom element ids to match those that'll be generated
15
+ # by the error summary.
16
+ # @param object [ActiveRecord::Base,ActiveModel::Model,Object] the object that we want to
17
+ # generate an id for
18
+ # @param object_name [Symbol] the object's name, the singular version of the object's class
19
+ # name, e.g., +Person+ is +:person+.
20
+ # @param attribute_name [Symbol] the attribute we're generating an id for
21
+ # @param value [Object] the value of the attribute. Only necessary for fields with
22
+ # multiple form elements like radio buttons and checkboxes
23
+ # @param link_errors [Boolean] toggles whether or not to override the field id with the
24
+ # error id when there are errors on the +object+. Only relevant for radio buttons
25
+ # and check boxes.
26
+ def govuk_field_id(object, attribute_name, object_name = nil, value: nil, link_errors: true)
27
+ (object_name = retrieve_object_name(object)) if object_name.nil?
28
+
29
+ proxy_base(object, object_name, attribute_name, value: value).field_id(link_errors: link_errors)
30
+ end
31
+
32
+ # Renders an error summary
33
+ # @param object [ActiveRecord::Base,ActiveModel::Model,Object] the object we'll be rendering
34
+ # the errors for
35
+ # @param object_name [Symbol] the object's name, the singular version of the object's class
36
+ # name, e.g., +Person+ is +:person+. If none is supplied we'll try to infer it from
37
+ # the object, so it'll probably be necessary for regular Ruby objects
38
+ # @option args [Array] options passed through to the builder's +#govuk_error_summary+
39
+ # @option kwargs [Hash] keyword options passed through to the builder's +#govuk_error_summary+
40
+ #
41
+ # @example
42
+ # = govuk_error_summary(@registration)
43
+ #
44
+ # @see https://design-system.service.gov.uk/components/error-summary/ GOV.UK error summary
45
+ def govuk_error_summary(object, object_name = nil, *args, **kwargs)
46
+ (object_name = retrieve_object_name(object)) if object_name.nil?
47
+
48
+ proxy_builder(object, object_name, self, {}).govuk_error_summary(*args, **kwargs)
49
+ end
50
+
51
+ private
52
+
53
+ def proxy_base(object, object_name, attribute_name, value: nil)
54
+ GOVUKDesignSystemFormBuilder::Proxy.new(object, object_name, attribute_name, value: value)
55
+ end
56
+
57
+ def proxy_builder(object, object_name, template, options)
58
+ GOVUKDesignSystemFormBuilder::FormBuilderProxy.new(object_name, object, template, options)
59
+ end
60
+
61
+ def retrieve_object_name(object)
62
+ object.to_model.model_name.singular
63
+ end
64
+ end
65
+ end
@@ -2,13 +2,10 @@ module GOVUKDesignSystemFormBuilder
2
2
  module Elements
3
3
  module CheckBoxes
4
4
  class FieldsetCheckBox < Base
5
- using PrefixableArray
6
-
7
5
  include Traits::Label
8
6
  include Traits::Hint
9
- include Traits::FieldsetItem
10
- include Traits::Conditional
11
7
  include Traits::HTMLAttributes
8
+ include Traits::FieldsetItem
12
9
 
13
10
  def initialize(builder, object_name, attribute_name, value, unchecked_value, label:, hint:, link_errors:, multiple:, **kwargs, &block)
14
11
  super(builder, object_name, attribute_name)
@@ -21,49 +18,22 @@ module GOVUKDesignSystemFormBuilder
21
18
  @link_errors = link_errors
22
19
  @html_attributes = kwargs
23
20
 
24
- if block_given?
25
- @conditional_content = wrap_conditional(block)
26
- @conditional_id = conditional_id
27
- end
28
- end
29
-
30
- def html
31
- safe_join([item, @conditional_content])
21
+ conditional_content(&block)
32
22
  end
33
23
 
34
24
  private
35
25
 
36
- def item
37
- tag.div(class: %(#{brand}-checkboxes__item)) do
38
- safe_join([check_box, label_element, hint_element])
39
- end
26
+ def input_type
27
+ :checkboxes
40
28
  end
41
29
 
42
- def check_box
30
+ def input
43
31
  @builder.check_box(@attribute_name, attributes(@html_attributes), @value, @unchecked_value)
44
32
  end
45
33
 
46
- def options
47
- {
48
- id: field_id(link_errors: @link_errors),
49
- class: classes,
50
- multiple: @multiple,
51
- aria: { describedby: [hint_id] },
52
- data: { 'aria-controls' => @conditional_id }
53
- }
54
- end
55
-
56
- def classes
57
- %w(checkboxes__input).prefix(brand)
58
- end
59
-
60
34
  def fieldset_options
61
35
  { checkbox: true }
62
36
  end
63
-
64
- def conditional_classes
65
- %w(checkboxes__conditional checkboxes__conditional--hidden).prefix(brand)
66
- end
67
37
  end
68
38
  end
69
39
  end
@@ -2,13 +2,10 @@ module GOVUKDesignSystemFormBuilder
2
2
  module Elements
3
3
  module Radios
4
4
  class FieldsetRadioButton < Base
5
- using PrefixableArray
6
-
7
5
  include Traits::Label
8
6
  include Traits::Hint
9
- include Traits::FieldsetItem
10
- include Traits::Conditional
11
7
  include Traits::HTMLAttributes
8
+ include Traits::FieldsetItem
12
9
 
13
10
  def initialize(builder, object_name, attribute_name, value, label:, hint:, link_errors:, **kwargs, &block)
14
11
  super(builder, object_name, attribute_name)
@@ -19,43 +16,21 @@ module GOVUKDesignSystemFormBuilder
19
16
  @link_errors = has_errors? && link_errors
20
17
  @html_attributes = kwargs
21
18
 
22
- if block_given?
23
- @conditional_content = wrap_conditional(block)
24
- @conditional_id = conditional_id
25
- end
26
- end
27
-
28
- def html
29
- safe_join([radio, @conditional_content])
19
+ conditional_content(&block)
30
20
  end
31
21
 
32
22
  private
33
23
 
34
- def radio
35
- tag.div(class: %(#{brand}-radios__item)) do
36
- safe_join([input, label_element, hint_element])
37
- end
38
- end
39
-
40
- def fieldset_options
41
- { radio: true }
24
+ def input_type
25
+ :radios
42
26
  end
43
27
 
44
28
  def input
45
29
  @builder.radio_button(@attribute_name, @value, **attributes(@html_attributes))
46
30
  end
47
31
 
48
- def options
49
- {
50
- id: field_id(link_errors: @link_errors),
51
- aria: { describedby: [hint_id] },
52
- data: { 'aria-controls' => @conditional_id },
53
- class: %w(radios__input).prefix(brand)
54
- }
55
- end
56
-
57
- def conditional_classes
58
- %w(radios__conditional radios__conditional--hidden).prefix(brand)
32
+ def fieldset_options
33
+ { radio: true }
59
34
  end
60
35
  end
61
36
  end
@@ -0,0 +1,13 @@
1
+ require_relative 'base'
2
+
3
+ module GOVUKDesignSystemFormBuilder
4
+ class Proxy < GOVUKDesignSystemFormBuilder::Base
5
+ NullBuilder = Struct.new(:object)
6
+
7
+ def initialize(object, object_name, attribute_name, value: nil)
8
+ super(NullBuilder.new(object), object_name, attribute_name)
9
+
10
+ @value = value
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ module GOVUKDesignSystemFormBuilder
2
+ module PrefixableArray
3
+ refine Array do
4
+ def prefix(text, delimiter: '-')
5
+ map { |item| [text, item].join(delimiter.to_s) }
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,8 +1,38 @@
1
1
  module GOVUKDesignSystemFormBuilder
2
2
  module Traits
3
3
  module FieldsetItem
4
+ using PrefixableArray
5
+
6
+ def html
7
+ safe_join([item, @conditional])
8
+ end
9
+
4
10
  private
5
11
 
12
+ def class_prefix
13
+ %(#{brand}-#{input_type})
14
+ end
15
+
16
+ def item
17
+ tag.div(class: %(#{class_prefix}__item)) do
18
+ safe_join([input, label_element, hint_element])
19
+ end
20
+ end
21
+
22
+ def options
23
+ {
24
+ id: field_id(link_errors: @link_errors),
25
+ class: classes,
26
+ multiple: @multiple,
27
+ aria: { describedby: [hint_id] },
28
+ data: { 'aria-controls' => @conditional_id }
29
+ }
30
+ end
31
+
32
+ def classes
33
+ [%(#{class_prefix}__input)]
34
+ end
35
+
6
36
  def label_element
7
37
  @label_element ||= if @label.nil?
8
38
  Elements::Null.new
@@ -26,6 +56,27 @@ module GOVUKDesignSystemFormBuilder
26
56
  def hint_options
27
57
  { value: @value }.merge(fieldset_options)
28
58
  end
59
+
60
+ def conditional_id
61
+ build_id('conditional')
62
+ end
63
+
64
+ def conditional_content(&block)
65
+ if (conditional_block_content = block_given? && (capture { block.call }).presence)
66
+ @conditional = conditional_container(conditional_block_content)
67
+ @conditional_id = conditional_id
68
+ end
69
+ end
70
+
71
+ def conditional_container(content)
72
+ tag.div(class: conditional_classes, id: conditional_id) do
73
+ content
74
+ end
75
+ end
76
+
77
+ def conditional_classes
78
+ %w(__conditional __conditional--hidden).prefix(class_prefix, delimiter: nil)
79
+ end
29
80
  end
30
81
  end
31
82
  end
@@ -1,11 +1,17 @@
1
1
  module GOVUKDesignSystemFormBuilder
2
2
  module Traits
3
3
  module HTMLAttributes
4
- # Attributes eases working with default and custom attributes by
4
+ # Attributes eases working with default and custom attributes by:
5
5
  # * deeply merging them so both the default (required) attributes are
6
6
  # present
7
7
  # * joins the arrays into strings to maintain Rails 6.0.3 compatibility
8
8
  class Attributes
9
+ # Rather than attempt to combine these attributes, just overwrite the
10
+ # form internally-generated values with those that are passed in. This
11
+ # prevents the merge/unique value logic from affecting the content
12
+ # (i.e. by remvoving duplicated words).
13
+ UNMERGEABLE = [%i(id), %i(value), %i(title), %i(alt), %i(href), %i(aria label)].freeze
14
+
9
15
  def initialize(defaults, custom)
10
16
  @merged = defaults.deeper_merge(deep_split_values(custom))
11
17
  end
@@ -16,19 +22,25 @@ module GOVUKDesignSystemFormBuilder
16
22
 
17
23
  private
18
24
 
19
- def deep_split_values(hash)
25
+ def deep_split_values(hash, parent = nil)
20
26
  hash.each.with_object({}) do |(key, value), result|
21
27
  result[key] = case value
22
28
  when Hash
23
- deep_split_values(value)
29
+ deep_split_values(value, key)
24
30
  when String
25
- value.split
31
+ split_mergeable(key, value, parent)
26
32
  else
27
33
  value
28
34
  end
29
35
  end
30
36
  end
31
37
 
38
+ def split_mergeable(key, value, parent = nil)
39
+ return value if [parent, key].compact.in?(UNMERGEABLE)
40
+
41
+ value.split
42
+ end
43
+
32
44
  def deep_join_values(hash)
33
45
  hash.each.with_object({}) do |(key, value), result|
34
46
  result[key] = case value
@@ -1,3 +1,3 @@
1
1
  module GOVUKDesignSystemFormBuilder
2
- VERSION = '2.5.0'.freeze
2
+ VERSION = '2.6.0b1'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: govuk_design_system_formbuilder
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.0
4
+ version: 2.6.0b1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Yates
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-13 00:00:00.000000000 Z
11
+ date: 2021-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: deep_merge
@@ -70,16 +70,16 @@ dependencies:
70
70
  name: rubocop-govuk
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '='
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 4.0.0.pre.1
75
+ version: 4.0.0
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '='
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 4.0.0.pre.1
82
+ version: 4.0.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: pry
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -268,6 +268,20 @@ dependencies:
268
268
  - - "~>"
269
269
  - !ruby/object:Gem::Version
270
270
  version: 1.7.0
271
+ - !ruby/object:Gem::Dependency
272
+ name: slim_lint
273
+ requirement: !ruby/object:Gem::Requirement
274
+ requirements:
275
+ - - "~>"
276
+ - !ruby/object:Gem::Version
277
+ version: 0.21.1
278
+ type: :development
279
+ prerelease: false
280
+ version_requirements: !ruby/object:Gem::Requirement
281
+ requirements:
282
+ - - "~>"
283
+ - !ruby/object:Gem::Version
284
+ version: 0.21.1
271
285
  description: A Rails form builder that generates form inputs adhering to the GOV.UK
272
286
  Design System
273
287
  email:
@@ -281,6 +295,7 @@ files:
281
295
  - lib/govuk_design_system_formbuilder.rb
282
296
  - lib/govuk_design_system_formbuilder/base.rb
283
297
  - lib/govuk_design_system_formbuilder/builder.rb
298
+ - lib/govuk_design_system_formbuilder/builder_helper.rb
284
299
  - lib/govuk_design_system_formbuilder/containers/button_group.rb
285
300
  - lib/govuk_design_system_formbuilder/containers/character_count.rb
286
301
  - lib/govuk_design_system_formbuilder/containers/check_boxes.rb
@@ -316,9 +331,10 @@ files:
316
331
  - lib/govuk_design_system_formbuilder/elements/select.rb
317
332
  - lib/govuk_design_system_formbuilder/elements/submit.rb
318
333
  - lib/govuk_design_system_formbuilder/elements/text_area.rb
334
+ - lib/govuk_design_system_formbuilder/proxy.rb
335
+ - lib/govuk_design_system_formbuilder/refinements/prefixable_array.rb
319
336
  - lib/govuk_design_system_formbuilder/traits/caption.rb
320
337
  - lib/govuk_design_system_formbuilder/traits/collection_item.rb
321
- - lib/govuk_design_system_formbuilder/traits/conditional.rb
322
338
  - lib/govuk_design_system_formbuilder/traits/error.rb
323
339
  - lib/govuk_design_system_formbuilder/traits/fieldset_item.rb
324
340
  - lib/govuk_design_system_formbuilder/traits/hint.rb
@@ -349,9 +365,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
349
365
  version: '0'
350
366
  required_rubygems_version: !ruby/object:Gem::Requirement
351
367
  requirements:
352
- - - ">="
368
+ - - ">"
353
369
  - !ruby/object:Gem::Version
354
- version: '0'
370
+ version: 1.3.1
355
371
  requirements: []
356
372
  rubygems_version: 3.1.6
357
373
  signing_key:
@@ -1,17 +0,0 @@
1
- module GOVUKDesignSystemFormBuilder
2
- module Traits
3
- module Conditional
4
- private
5
-
6
- def conditional_id
7
- build_id('conditional')
8
- end
9
-
10
- def wrap_conditional(block)
11
- tag.div(class: conditional_classes, id: conditional_id) do
12
- capture { block.call }
13
- end
14
- end
15
- end
16
- end
17
- end