simple_form 3.4.0 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +118 -8
  3. data/MIT-LICENSE +2 -1
  4. data/README.md +235 -67
  5. data/lib/generators/simple_form/install_generator.rb +1 -0
  6. data/lib/generators/simple_form/templates/README +2 -3
  7. data/lib/generators/simple_form/templates/_form.html.erb +2 -0
  8. data/lib/generators/simple_form/templates/_form.html.haml +2 -0
  9. data/lib/generators/simple_form/templates/_form.html.slim +1 -0
  10. data/lib/generators/simple_form/templates/config/initializers/simple_form.rb +14 -7
  11. data/lib/generators/simple_form/templates/config/initializers/simple_form_bootstrap.rb +360 -74
  12. data/lib/generators/simple_form/templates/config/initializers/simple_form_foundation.rb +20 -8
  13. data/lib/simple_form/action_view_extensions/builder.rb +1 -0
  14. data/lib/simple_form/action_view_extensions/form_helper.rb +1 -0
  15. data/lib/simple_form/components/errors.rb +15 -2
  16. data/lib/simple_form/components/hints.rb +1 -0
  17. data/lib/simple_form/components/html5.rb +1 -0
  18. data/lib/simple_form/components/label_input.rb +2 -1
  19. data/lib/simple_form/components/labels.rb +12 -7
  20. data/lib/simple_form/components/maxlength.rb +4 -17
  21. data/lib/simple_form/components/min_max.rb +1 -0
  22. data/lib/simple_form/components/minlength.rb +5 -18
  23. data/lib/simple_form/components/pattern.rb +1 -0
  24. data/lib/simple_form/components/placeholders.rb +2 -1
  25. data/lib/simple_form/components/readonly.rb +1 -0
  26. data/lib/simple_form/components.rb +1 -0
  27. data/lib/simple_form/error_notification.rb +1 -0
  28. data/lib/simple_form/form_builder.rb +104 -29
  29. data/lib/simple_form/helpers/autofocus.rb +1 -0
  30. data/lib/simple_form/helpers/disabled.rb +1 -0
  31. data/lib/simple_form/helpers/readonly.rb +1 -0
  32. data/lib/simple_form/helpers/required.rb +1 -0
  33. data/lib/simple_form/helpers/validators.rb +2 -1
  34. data/lib/simple_form/helpers.rb +1 -0
  35. data/lib/simple_form/inputs/base.rb +24 -5
  36. data/lib/simple_form/inputs/block_input.rb +1 -0
  37. data/lib/simple_form/inputs/boolean_input.rb +4 -2
  38. data/lib/simple_form/inputs/collection_check_boxes_input.rb +3 -2
  39. data/lib/simple_form/inputs/collection_input.rb +6 -7
  40. data/lib/simple_form/inputs/collection_radio_buttons_input.rb +2 -1
  41. data/lib/simple_form/inputs/collection_select_input.rb +1 -0
  42. data/lib/simple_form/inputs/color_input.rb +14 -0
  43. data/lib/simple_form/inputs/date_time_input.rb +1 -0
  44. data/lib/simple_form/inputs/file_input.rb +1 -0
  45. data/lib/simple_form/inputs/grouped_collection_select_input.rb +1 -0
  46. data/lib/simple_form/inputs/hidden_input.rb +1 -0
  47. data/lib/simple_form/inputs/numeric_input.rb +1 -0
  48. data/lib/simple_form/inputs/password_input.rb +1 -0
  49. data/lib/simple_form/inputs/priority_input.rb +1 -4
  50. data/lib/simple_form/inputs/range_input.rb +1 -0
  51. data/lib/simple_form/inputs/rich_text_area_input.rb +12 -0
  52. data/lib/simple_form/inputs/string_input.rb +2 -1
  53. data/lib/simple_form/inputs/text_input.rb +1 -0
  54. data/lib/simple_form/inputs.rb +3 -0
  55. data/lib/simple_form/map_type.rb +1 -0
  56. data/lib/simple_form/railtie.rb +1 -0
  57. data/lib/simple_form/tags.rb +7 -2
  58. data/lib/simple_form/version.rb +2 -1
  59. data/lib/simple_form/wrappers/builder.rb +1 -0
  60. data/lib/simple_form/wrappers/leaf.rb +2 -1
  61. data/lib/simple_form/wrappers/many.rb +1 -0
  62. data/lib/simple_form/wrappers/root.rb +9 -2
  63. data/lib/simple_form/wrappers/single.rb +2 -1
  64. data/lib/simple_form/wrappers.rb +1 -0
  65. data/lib/simple_form.rb +79 -11
  66. data/test/action_view_extensions/builder_test.rb +28 -9
  67. data/test/action_view_extensions/form_helper_test.rb +3 -2
  68. data/test/components/custom_components_test.rb +62 -0
  69. data/test/components/label_test.rb +33 -8
  70. data/test/form_builder/association_test.rb +33 -2
  71. data/test/form_builder/button_test.rb +1 -0
  72. data/test/form_builder/error_notification_test.rb +1 -0
  73. data/test/form_builder/error_test.rb +12 -0
  74. data/test/form_builder/general_test.rb +75 -13
  75. data/test/form_builder/hint_test.rb +6 -0
  76. data/test/form_builder/input_field_test.rb +30 -10
  77. data/test/form_builder/label_test.rb +10 -4
  78. data/test/form_builder/wrapper_test.rb +32 -5
  79. data/test/generators/simple_form_generator_test.rb +4 -3
  80. data/test/inputs/boolean_input_test.rb +17 -0
  81. data/test/inputs/collection_check_boxes_input_test.rb +38 -18
  82. data/test/inputs/collection_radio_buttons_input_test.rb +48 -28
  83. data/test/inputs/collection_select_input_test.rb +46 -43
  84. data/test/inputs/color_input_test.rb +10 -0
  85. data/test/inputs/datetime_input_test.rb +7 -16
  86. data/test/inputs/disabled_test.rb +14 -0
  87. data/test/inputs/discovery_test.rb +22 -0
  88. data/test/inputs/file_input_test.rb +1 -0
  89. data/test/inputs/general_test.rb +3 -2
  90. data/test/inputs/grouped_collection_select_input_test.rb +11 -10
  91. data/test/inputs/hidden_input_test.rb +1 -0
  92. data/test/inputs/numeric_input_test.rb +2 -1
  93. data/test/inputs/priority_input_test.rb +7 -14
  94. data/test/inputs/readonly_test.rb +1 -0
  95. data/test/inputs/required_test.rb +1 -0
  96. data/test/inputs/rich_text_area_input_test.rb +15 -0
  97. data/test/inputs/string_input_test.rb +10 -16
  98. data/test/inputs/text_input_test.rb +1 -0
  99. data/test/simple_form_test.rb +1 -0
  100. data/test/support/discovery_inputs.rb +8 -0
  101. data/test/support/misc_helpers.rb +22 -1
  102. data/test/support/mock_controller.rb +7 -1
  103. data/test/support/models.rb +80 -18
  104. data/test/test_helper.rb +9 -4
  105. metadata +49 -55
  106. data/lib/simple_form/i18n_cache.rb +0 -22
@@ -1,5 +1,7 @@
1
+ -# frozen_string_literal: true
1
2
  = simple_form_for(@<%= singular_table_name %>) do |f|
2
3
  = f.error_notification
4
+ = f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present?
3
5
 
4
6
  .form-inputs
5
7
  <%- attributes.each do |attribute| -%>
@@ -1,5 +1,6 @@
1
1
  = simple_form_for(@<%= singular_table_name %>) do |f|
2
2
  = f.error_notification
3
+ = f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present?
3
4
 
4
5
  .form-inputs
5
6
  <%- attributes.each do |attribute| -%>
@@ -1,3 +1,11 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Uncomment this and change the path if necessary to include your own
4
+ # components.
5
+ # See https://github.com/heartcombo/simple_form#custom-components to know
6
+ # more about custom components.
7
+ # Dir[Rails.root.join('lib/components/**/*.rb')].each { |f| require f }
8
+ #
1
9
  # Use this setup block to configure all options available in SimpleForm.
2
10
  SimpleForm.setup do |config|
3
11
  # Wrappers are used by the form builder to generate a
@@ -6,7 +14,7 @@ SimpleForm.setup do |config|
6
14
  # stack. The options given below are used to wrap the
7
15
  # whole input.
8
16
  config.wrappers :default, class: :input,
9
- hint_class: :field_with_hint, error_class: :field_with_errors do |b|
17
+ hint_class: :field_with_hint, error_class: :field_with_errors, valid_class: :field_without_errors do |b|
10
18
  ## Extensions enabled by default
11
19
  # Any of these extensions can be disabled for a
12
20
  # given input by passing: `f.input EXTENSION_NAME => false`.
@@ -44,6 +52,7 @@ SimpleForm.setup do |config|
44
52
  b.optional :readonly
45
53
 
46
54
  ## Inputs
55
+ # b.use :input, class: 'input', error_class: 'is-invalid', valid_class: 'is-valid'
47
56
  b.use :label_input
48
57
  b.use :hint, wrap_with: { tag: :span, class: :hint }
49
58
  b.use :error, wrap_with: { tag: :span, class: :error }
@@ -78,9 +87,6 @@ SimpleForm.setup do |config|
78
87
  # CSS class to add for error notification helper.
79
88
  config.error_notification_class = 'error_notification'
80
89
 
81
- # ID to add for error notification helper.
82
- # config.error_notification_id = nil
83
-
84
90
  # Series of attempts to detect a default label method for collection.
85
91
  # config.collection_label_methods = [ :to_label, :name, :title, :to_s ]
86
92
 
@@ -123,9 +129,6 @@ SimpleForm.setup do |config|
123
129
  # change this configuration to true.
124
130
  config.browser_validations = false
125
131
 
126
- # Collection of methods to detect if a file type was given.
127
- # config.file_methods = [ :mounted_as, :file?, :public_filename ]
128
-
129
132
  # Custom mappings for input types. This should be a hash containing a regexp
130
133
  # to match as key, and the input type that will be used when the field name
131
134
  # matches the regexp as value.
@@ -166,4 +169,8 @@ SimpleForm.setup do |config|
166
169
 
167
170
  # Defines which i18n scope will be used in Simple Form.
168
171
  # config.i18n_scope = 'simple_form'
172
+
173
+ # Defines validation classes to the input_field. By default it's nil.
174
+ # config.input_field_valid_class = 'is-valid'
175
+ # config.input_field_error_class = 'is-invalid'
169
176
  end
@@ -1,10 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Please do not make direct changes to this file!
4
+ # This generator is maintained by the community around simple_form-bootstrap:
5
+ # https://github.com/rafaelfranca/simple_form-bootstrap
6
+ # All future development, tests, and organization should happen there.
7
+ # Background history: https://github.com/heartcombo/simple_form/issues/1561
8
+
9
+ # Uncomment this and change the path if necessary to include your own
10
+ # components.
11
+ # See https://github.com/heartcombo/simple_form#custom-components
12
+ # to know more about custom components.
13
+ # Dir[Rails.root.join('lib/components/**/*.rb')].each { |f| require f }
14
+
1
15
  # Use this setup block to configure all options available in SimpleForm.
2
16
  SimpleForm.setup do |config|
17
+ # Default class for buttons
18
+ config.button_class = 'btn'
19
+
20
+ # Define the default class of the input wrapper of the boolean input.
21
+ config.boolean_label_class = 'form-check-label'
22
+
23
+ # How the label text should be generated altogether with the required text.
24
+ config.label_text = lambda { |label, required, explicit_label| "#{label} #{required}" }
25
+
26
+ # Define the way to render check boxes / radio buttons with labels.
27
+ config.boolean_style = :inline
28
+
29
+ # You can wrap each item in a collection of radio/check boxes with a tag
30
+ config.item_wrapper_tag = :div
31
+
32
+ # Defines if the default input wrapper class should be included in radio
33
+ # collection wrappers.
34
+ config.include_default_input_wrapper_class = false
35
+
36
+ # CSS class to add for error notification helper.
3
37
  config.error_notification_class = 'alert alert-danger'
4
- config.button_class = 'btn btn-default'
5
- config.boolean_label_class = nil
6
38
 
7
- config.wrappers :vertical_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
39
+ # Method used to tidy up errors. Specify any Rails Array method.
40
+ # :first lists the first message for each field.
41
+ # :to_sentence to list all errors for each field.
42
+ config.error_method = :to_sentence
43
+
44
+ # add validation classes to `input_field`
45
+ config.input_field_error_class = 'is-invalid'
46
+ config.input_field_valid_class = 'is-valid'
47
+
48
+
49
+ # vertical forms
50
+ #
51
+ # vertical default_wrapper
52
+ config.wrappers :vertical_form, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
8
53
  b.use :html5
9
54
  b.use :placeholder
10
55
  b.optional :maxlength
@@ -12,48 +57,90 @@ SimpleForm.setup do |config|
12
57
  b.optional :pattern
13
58
  b.optional :min_max
14
59
  b.optional :readonly
15
- b.use :label, class: 'control-label'
60
+ b.use :label
61
+ b.use :input, class: 'form-control', error_class: 'is-invalid', valid_class: 'is-valid'
62
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
63
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
64
+ end
65
+
66
+ # vertical input for boolean
67
+ config.wrappers :vertical_boolean, tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
68
+ b.use :html5
69
+ b.optional :readonly
70
+ b.wrapper :form_check_wrapper, tag: 'div', class: 'form-check' do |bb|
71
+ bb.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
72
+ bb.use :label, class: 'form-check-label'
73
+ bb.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
74
+ bb.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
75
+ end
76
+ end
77
+
78
+ # vertical input for radio buttons and check boxes
79
+ config.wrappers :vertical_collection, item_wrapper_class: 'form-check', item_label_class: 'form-check-label', tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
80
+ b.use :html5
81
+ b.optional :readonly
82
+ b.wrapper :legend_tag, tag: 'legend', class: 'col-form-label pt-0' do |ba|
83
+ ba.use :label_text
84
+ end
85
+ b.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
86
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
87
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
88
+ end
16
89
 
17
- b.use :input, class: 'form-control'
18
- b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
19
- b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
90
+ # vertical input for inline radio buttons and check boxes
91
+ config.wrappers :vertical_collection_inline, item_wrapper_class: 'form-check form-check-inline', item_label_class: 'form-check-label', tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
92
+ b.use :html5
93
+ b.optional :readonly
94
+ b.wrapper :legend_tag, tag: 'legend', class: 'col-form-label pt-0' do |ba|
95
+ ba.use :label_text
96
+ end
97
+ b.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
98
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
99
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
20
100
  end
21
101
 
22
- config.wrappers :vertical_file_input, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
102
+ # vertical file input
103
+ config.wrappers :vertical_file, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
23
104
  b.use :html5
24
105
  b.use :placeholder
25
106
  b.optional :maxlength
26
107
  b.optional :minlength
27
108
  b.optional :readonly
28
- b.use :label, class: 'control-label'
29
-
30
- b.use :input
31
- b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
32
- b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
109
+ b.use :label
110
+ b.use :input, class: 'form-control-file', error_class: 'is-invalid', valid_class: 'is-valid'
111
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
112
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
33
113
  end
34
114
 
35
- config.wrappers :vertical_boolean, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
115
+ # vertical multi select
116
+ config.wrappers :vertical_multi_select, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
36
117
  b.use :html5
37
118
  b.optional :readonly
38
-
39
- b.wrapper tag: 'div', class: 'checkbox' do |ba|
40
- ba.use :label_input
119
+ b.use :label
120
+ b.wrapper tag: 'div', class: 'd-flex flex-row justify-content-between align-items-center' do |ba|
121
+ ba.use :input, class: 'form-control mx-1', error_class: 'is-invalid', valid_class: 'is-valid'
41
122
  end
42
-
43
- b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
44
- b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
123
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
124
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
45
125
  end
46
126
 
47
- config.wrappers :vertical_radio_and_checkboxes, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
127
+ # vertical range input
128
+ config.wrappers :vertical_range, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
48
129
  b.use :html5
130
+ b.use :placeholder
49
131
  b.optional :readonly
50
- b.use :label, class: 'control-label'
51
- b.use :input
52
- b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
53
- b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
132
+ b.optional :step
133
+ b.use :label
134
+ b.use :input, class: 'form-control-range', error_class: 'is-invalid', valid_class: 'is-valid'
135
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
136
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
54
137
  end
55
138
 
56
- config.wrappers :horizontal_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
139
+
140
+ # horizontal forms
141
+ #
142
+ # horizontal default_wrapper
143
+ config.wrappers :horizontal_form, tag: 'div', class: 'form-group row', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
57
144
  b.use :html5
58
145
  b.use :placeholder
59
146
  b.optional :maxlength
@@ -61,58 +148,244 @@ SimpleForm.setup do |config|
61
148
  b.optional :pattern
62
149
  b.optional :min_max
63
150
  b.optional :readonly
64
- b.use :label, class: 'col-sm-3 control-label'
151
+ b.use :label, class: 'col-sm-3 col-form-label'
152
+ b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |ba|
153
+ ba.use :input, class: 'form-control', error_class: 'is-invalid', valid_class: 'is-valid'
154
+ ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
155
+ ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
156
+ end
157
+ end
158
+
159
+ # horizontal input for boolean
160
+ config.wrappers :horizontal_boolean, tag: 'div', class: 'form-group row', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
161
+ b.use :html5
162
+ b.optional :readonly
163
+ b.wrapper tag: 'label', class: 'col-sm-3' do |ba|
164
+ ba.use :label_text
165
+ end
166
+ b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |wr|
167
+ wr.wrapper :form_check_wrapper, tag: 'div', class: 'form-check' do |bb|
168
+ bb.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
169
+ bb.use :label, class: 'form-check-label'
170
+ bb.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
171
+ bb.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
172
+ end
173
+ end
174
+ end
65
175
 
66
- b.wrapper tag: 'div', class: 'col-sm-9' do |ba|
67
- ba.use :input, class: 'form-control'
68
- ba.use :error, wrap_with: { tag: 'span', class: 'help-block' }
69
- ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
176
+ # horizontal input for radio buttons and check boxes
177
+ config.wrappers :horizontal_collection, item_wrapper_class: 'form-check', item_label_class: 'form-check-label', tag: 'div', class: 'form-group row', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
178
+ b.use :html5
179
+ b.optional :readonly
180
+ b.use :label, class: 'col-sm-3 col-form-label pt-0'
181
+ b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |ba|
182
+ ba.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
183
+ ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
184
+ ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
70
185
  end
71
186
  end
72
187
 
73
- config.wrappers :horizontal_file_input, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
188
+ # horizontal input for inline radio buttons and check boxes
189
+ config.wrappers :horizontal_collection_inline, item_wrapper_class: 'form-check form-check-inline', item_label_class: 'form-check-label', tag: 'div', class: 'form-group row', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
190
+ b.use :html5
191
+ b.optional :readonly
192
+ b.use :label, class: 'col-sm-3 col-form-label pt-0'
193
+ b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |ba|
194
+ ba.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
195
+ ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
196
+ ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
197
+ end
198
+ end
199
+
200
+ # horizontal file input
201
+ config.wrappers :horizontal_file, tag: 'div', class: 'form-group row', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
74
202
  b.use :html5
75
203
  b.use :placeholder
76
204
  b.optional :maxlength
77
205
  b.optional :minlength
78
206
  b.optional :readonly
79
- b.use :label, class: 'col-sm-3 control-label'
207
+ b.use :label, class: 'col-sm-3 col-form-label'
208
+ b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |ba|
209
+ ba.use :input, error_class: 'is-invalid', valid_class: 'is-valid'
210
+ ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
211
+ ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
212
+ end
213
+ end
214
+
215
+ # horizontal multi select
216
+ config.wrappers :horizontal_multi_select, tag: 'div', class: 'form-group row', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
217
+ b.use :html5
218
+ b.optional :readonly
219
+ b.use :label, class: 'col-sm-3 col-form-label'
220
+ b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |ba|
221
+ ba.wrapper tag: 'div', class: 'd-flex flex-row justify-content-between align-items-center' do |bb|
222
+ bb.use :input, class: 'form-control mx-1', error_class: 'is-invalid', valid_class: 'is-valid'
223
+ end
224
+ ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
225
+ ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
226
+ end
227
+ end
80
228
 
81
- b.wrapper tag: 'div', class: 'col-sm-9' do |ba|
82
- ba.use :input
83
- ba.use :error, wrap_with: { tag: 'span', class: 'help-block' }
84
- ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
229
+ # horizontal range input
230
+ config.wrappers :horizontal_range, tag: 'div', class: 'form-group row', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
231
+ b.use :html5
232
+ b.use :placeholder
233
+ b.optional :readonly
234
+ b.optional :step
235
+ b.use :label, class: 'col-sm-3 col-form-label'
236
+ b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |ba|
237
+ ba.use :input, class: 'form-control-range', error_class: 'is-invalid', valid_class: 'is-valid'
238
+ ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
239
+ ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
85
240
  end
86
241
  end
87
242
 
88
- config.wrappers :horizontal_boolean, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
243
+
244
+ # inline forms
245
+ #
246
+ # inline default_wrapper
247
+ config.wrappers :inline_form, tag: 'span', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
89
248
  b.use :html5
249
+ b.use :placeholder
250
+ b.optional :maxlength
251
+ b.optional :minlength
252
+ b.optional :pattern
253
+ b.optional :min_max
90
254
  b.optional :readonly
255
+ b.use :label, class: 'sr-only'
91
256
 
92
- b.wrapper tag: 'div', class: 'col-sm-offset-3 col-sm-9' do |wr|
93
- wr.wrapper tag: 'div', class: 'checkbox' do |ba|
94
- ba.use :label_input
95
- end
257
+ b.use :input, class: 'form-control', error_class: 'is-invalid', valid_class: 'is-valid'
258
+ b.use :error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
259
+ b.optional :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
260
+ end
261
+
262
+ # inline input for boolean
263
+ config.wrappers :inline_boolean, tag: 'span', class: 'form-check mb-2 mr-sm-2', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
264
+ b.use :html5
265
+ b.optional :readonly
266
+ b.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
267
+ b.use :label, class: 'form-check-label'
268
+ b.use :error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
269
+ b.optional :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
270
+ end
96
271
 
97
- wr.use :error, wrap_with: { tag: 'span', class: 'help-block' }
98
- wr.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
272
+
273
+ # bootstrap custom forms
274
+ #
275
+ # custom input for boolean
276
+ config.wrappers :custom_boolean, tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
277
+ b.use :html5
278
+ b.optional :readonly
279
+ b.wrapper :form_check_wrapper, tag: 'div', class: 'custom-control custom-checkbox' do |bb|
280
+ bb.use :input, class: 'custom-control-input', error_class: 'is-invalid', valid_class: 'is-valid'
281
+ bb.use :label, class: 'custom-control-label'
282
+ bb.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
283
+ bb.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
99
284
  end
100
285
  end
101
286
 
102
- config.wrappers :horizontal_radio_and_checkboxes, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
287
+ # custom input switch for boolean
288
+ config.wrappers :custom_boolean_switch, tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
103
289
  b.use :html5
104
290
  b.optional :readonly
291
+ b.wrapper :form_check_wrapper, tag: 'div', class: 'custom-control custom-switch' do |bb|
292
+ bb.use :input, class: 'custom-control-input', error_class: 'is-invalid', valid_class: 'is-valid'
293
+ bb.use :label, class: 'custom-control-label'
294
+ bb.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
295
+ bb.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
296
+ end
297
+ end
105
298
 
106
- b.use :label, class: 'col-sm-3 control-label'
299
+ # custom input for radio buttons and check boxes
300
+ config.wrappers :custom_collection, item_wrapper_class: 'custom-control', item_label_class: 'custom-control-label', tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
301
+ b.use :html5
302
+ b.optional :readonly
303
+ b.wrapper :legend_tag, tag: 'legend', class: 'col-form-label pt-0' do |ba|
304
+ ba.use :label_text
305
+ end
306
+ b.use :input, class: 'custom-control-input', error_class: 'is-invalid', valid_class: 'is-valid'
307
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
308
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
309
+ end
107
310
 
108
- b.wrapper tag: 'div', class: 'col-sm-9' do |ba|
109
- ba.use :input
110
- ba.use :error, wrap_with: { tag: 'span', class: 'help-block' }
111
- ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
311
+ # custom input for inline radio buttons and check boxes
312
+ config.wrappers :custom_collection_inline, item_wrapper_class: 'custom-control custom-control-inline', item_label_class: 'custom-control-label', tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
313
+ b.use :html5
314
+ b.optional :readonly
315
+ b.wrapper :legend_tag, tag: 'legend', class: 'col-form-label pt-0' do |ba|
316
+ ba.use :label_text
112
317
  end
318
+ b.use :input, class: 'custom-control-input', error_class: 'is-invalid', valid_class: 'is-valid'
319
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
320
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
113
321
  end
114
322
 
115
- config.wrappers :inline_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
323
+ # custom file input
324
+ config.wrappers :custom_file, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
325
+ b.use :html5
326
+ b.use :placeholder
327
+ b.optional :maxlength
328
+ b.optional :minlength
329
+ b.optional :readonly
330
+ b.use :label
331
+ b.wrapper :custom_file_wrapper, tag: 'div', class: 'custom-file' do |ba|
332
+ ba.use :input, class: 'custom-file-input', error_class: 'is-invalid', valid_class: 'is-valid'
333
+ ba.use :label, class: 'custom-file-label'
334
+ ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
335
+ end
336
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
337
+ end
338
+
339
+ # custom multi select
340
+ config.wrappers :custom_multi_select, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
341
+ b.use :html5
342
+ b.optional :readonly
343
+ b.use :label
344
+ b.wrapper tag: 'div', class: 'd-flex flex-row justify-content-between align-items-center' do |ba|
345
+ ba.use :input, class: 'custom-select mx-1', error_class: 'is-invalid', valid_class: 'is-valid'
346
+ end
347
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
348
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
349
+ end
350
+
351
+ # custom range input
352
+ config.wrappers :custom_range, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
353
+ b.use :html5
354
+ b.use :placeholder
355
+ b.optional :readonly
356
+ b.optional :step
357
+ b.use :label
358
+ b.use :input, class: 'custom-range', error_class: 'is-invalid', valid_class: 'is-valid'
359
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
360
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
361
+ end
362
+
363
+
364
+ # Input Group - custom component
365
+ # see example app and config at https://github.com/rafaelfranca/simple_form-bootstrap
366
+ # config.wrappers :input_group, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
367
+ # b.use :html5
368
+ # b.use :placeholder
369
+ # b.optional :maxlength
370
+ # b.optional :minlength
371
+ # b.optional :pattern
372
+ # b.optional :min_max
373
+ # b.optional :readonly
374
+ # b.use :label
375
+ # b.wrapper :input_group_tag, tag: 'div', class: 'input-group' do |ba|
376
+ # ba.optional :prepend
377
+ # ba.use :input, class: 'form-control', error_class: 'is-invalid', valid_class: 'is-valid'
378
+ # ba.optional :append
379
+ # end
380
+ # b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
381
+ # b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
382
+ # end
383
+
384
+
385
+ # Floating Labels form
386
+ #
387
+ # floating labels default_wrapper
388
+ config.wrappers :floating_labels_form, tag: 'div', class: 'form-label-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
116
389
  b.use :html5
117
390
  b.use :placeholder
118
391
  b.optional :maxlength
@@ -120,35 +393,48 @@ SimpleForm.setup do |config|
120
393
  b.optional :pattern
121
394
  b.optional :min_max
122
395
  b.optional :readonly
123
- b.use :label, class: 'sr-only'
124
-
125
- b.use :input, class: 'form-control'
126
- b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
127
- b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
396
+ b.use :input, class: 'form-control', error_class: 'is-invalid', valid_class: 'is-valid'
397
+ b.use :label
398
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
399
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
128
400
  end
129
401
 
130
- config.wrappers :multi_select, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
402
+ # custom multi select
403
+ config.wrappers :floating_labels_select, tag: 'div', class: 'form-label-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
131
404
  b.use :html5
132
405
  b.optional :readonly
133
- b.use :label, class: 'control-label'
134
- b.wrapper tag: 'div', class: 'form-inline' do |ba|
135
- ba.use :input, class: 'form-control'
136
- ba.use :error, wrap_with: { tag: 'span', class: 'help-block' }
137
- ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
138
- end
406
+ b.use :input, class: 'custom-select', error_class: 'is-invalid', valid_class: 'is-valid'
407
+ b.use :label
408
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
409
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
139
410
  end
140
- # Wrappers for forms and inputs using the Bootstrap toolkit.
141
- # Check the Bootstrap docs (http://getbootstrap.com)
142
- # to learn about the different styles for forms and inputs,
143
- # buttons and other elements.
411
+
412
+
413
+ # The default wrapper to be used by the FormBuilder.
144
414
  config.default_wrapper = :vertical_form
415
+
416
+ # Custom wrappers for input types. This should be a hash containing an input
417
+ # type as key and the wrapper that will be used for all inputs with specified type.
145
418
  config.wrapper_mappings = {
146
- check_boxes: :vertical_radio_and_checkboxes,
147
- radio_buttons: :vertical_radio_and_checkboxes,
148
- file: :vertical_file_input,
149
- boolean: :vertical_boolean,
150
- datetime: :multi_select,
151
- date: :multi_select,
152
- time: :multi_select
419
+ boolean: :vertical_boolean,
420
+ check_boxes: :vertical_collection,
421
+ date: :vertical_multi_select,
422
+ datetime: :vertical_multi_select,
423
+ file: :vertical_file,
424
+ radio_buttons: :vertical_collection,
425
+ range: :vertical_range,
426
+ time: :vertical_multi_select
153
427
  }
428
+
429
+ # enable custom form wrappers
430
+ # config.wrapper_mappings = {
431
+ # boolean: :custom_boolean,
432
+ # check_boxes: :custom_collection,
433
+ # date: :custom_multi_select,
434
+ # datetime: :custom_multi_select,
435
+ # file: :custom_file,
436
+ # radio_buttons: :custom_collection,
437
+ # range: :custom_range,
438
+ # time: :custom_multi_select
439
+ # }
154
440
  end