view_component-form 0.2.4 → 0.2.5

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: e34a41ebc599bd19cfcb44df6531abea9f69d6e411654bd30f51214f5d9b5689
4
- data.tar.gz: 481a67aec41fb2ee179d9123f4140385a848ba2d1d92f0de0fdebb4eb8a07a8a
3
+ metadata.gz: bf9294810dc61eeda3187f0a15bd0fd41076a1aff08e35088123ff7b6394a7bc
4
+ data.tar.gz: 1e354c3e739a66eabb5d4e33627ab6393a6385deebc4fbf05fbb7fdff514d8ce
5
5
  SHA512:
6
- metadata.gz: 1e7e7d6496ce356fd2409cd67822187d0b7619d9d56ae6c5172ef26dcfbb8f65af9c9bfe4025d5c5bf2b01ceb784bd6ef97263e508ac50e1a732d9bbf670ac97
7
- data.tar.gz: 449e48d08d88438c70be0888074f68871dce0ebbc20b7bcfa45d35526c60e3dd30b0c32a7114cc54574969505469eb1e3b013836c69b92b10edeb33bdd6305b9
6
+ metadata.gz: 1ec60427e83e48970da97868e150f42796caeb0c4db320e6da67574aee28832e2d4c7fd540ecbdda3da3c6349e078d3a7038206ecd3c59934db58bc88fcc1a7e
7
+ data.tar.gz: '058769880aa90ff14e44c80e36e9db16c7eda9f0262c92112a025a16e208b5fcde83f79d2b011f82d3f8802abc7eff4155fdb146b629cfdb5557db89ee87b5f7'
data/CHANGELOG.md CHANGED
@@ -7,9 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
  ## [Unreleased]
8
8
  Nothing yet
9
9
 
10
+ ## [0.2.5] - 2023-05-01
11
+ ### Changed
12
+ - Split `Form::Builder` into modules, to allow including only some modules instead of inheriting the whole class (#134)
13
+ - Using the `Form::Builder` generator now creates the file in `app/helpers` by default, instead of `lib` previously, so that it's autoloaded by Rails without further configuration (#137)
14
+ - Support for `view_component` 3.0 (#136, #147)
15
+
16
+ ### Fixed
17
+ - Update dependencies (#128)
18
+ - Add Ruby 3.2 to CI (#128)
19
+ - Fix specs for Rails 7.1 (#128)
20
+
10
21
  ## [0.2.4] - 2022-04-27
11
22
  ### Changed
12
- - Add ruby 3.1 to CI (#123)
23
+ - Add Ruby 3.1 to CI (#123)
13
24
 
14
25
  ### Fixed
15
26
  - Fix `FileFieldComponent` options for `direct_upload` and `include_hidden` (#122)
@@ -88,7 +99,9 @@ Nothing yet
88
99
  - Add CHANGELOG (#50)
89
100
  - Add CI (#2)
90
101
 
91
- [Unreleased]: https://github.com/pantographe/view_component-form/compare/v0.2.3...HEAD
102
+ [Unreleased]: https://github.com/pantographe/view_component-form/compare/v0.2.5...HEAD
103
+ [0.2.5]: https://github.com/pantographe/view_component-form/compare/v0.2.4...v0.2.5
104
+ [0.2.4]: https://github.com/pantographe/view_component-form/compare/v0.2.3...v0.2.4
92
105
  [0.2.3]: https://github.com/pantographe/view_component-form/compare/v0.2.2...v0.2.3
93
106
  [0.2.2]: https://github.com/pantographe/view_component-form/compare/v0.2.1...v0.2.2
94
107
  [0.2.1]: https://github.com/pantographe/view_component-form/compare/v0.2.0...v0.2.1
data/README.md CHANGED
@@ -4,6 +4,10 @@
4
4
 
5
5
  :warning: **This is an early release: the API is subject to change until we reach `v1.0.0`.**
6
6
 
7
+ Development of this gem is sponsored by:
8
+
9
+ <a href="https://etamin.studio/?ref=view_component-form"><img src="https://etamin.studio/images/logo.svg" alt="Sponsored by Etamin Studio" width="184" height="22"></a>      <a href="https://pantographe.studio/?ref=view_component-form"><img src="https://static.s3.office.pantographe.cloud/logofull.svg" alt="Sponsored by Pantographe" width="156" height="25"></a>
10
+
7
11
  ## Compatibility
8
12
 
9
13
  This gem is tested on:
@@ -91,16 +95,16 @@ First, generate your own `FormBuilder`:
91
95
  ```console
92
96
  bin/rails generate vcf:builder CustomFormBuilder
93
97
 
94
- create lib/custom_form_builder.rb
98
+ create app/helpers/custom_form_builder.rb
95
99
  ```
96
100
 
97
101
  This allows you to pick the namespace your components will be loaded from.
98
102
 
99
103
  ```rb
100
- # lib/custom_form_builder.rb
104
+ # app/helpers/custom_form_builder.rb
101
105
  class CustomFormBuilder < ViewComponent::Form::Builder
102
106
  # Set the namespace you want to use for your own components
103
- namespace Custom::Form
107
+ namespace "Custom::Form"
104
108
  end
105
109
  ```
106
110
 
@@ -116,7 +120,32 @@ bin/rails generate vcf:builder AnotherCustomFormBuilder --namespace AnotherCusto
116
120
  # app/forms/another_custom_form_builder.rb
117
121
  class AnotherCustomFormBuilder < ViewComponent::Form::Builder
118
122
  # Set the namespace you want to use for your own components
119
- namespace AnotherCustom::Form
123
+ namespace "AnotherCustom::Form"
124
+ end
125
+ ```
126
+
127
+ Another approach is to include only some modules instead of inheriting from the whole class:
128
+
129
+ ```rb
130
+ # app/forms/modular_custom_form_builder.rb
131
+ class ModularCustomFormBuilder < ActionView::Helpers::FormBuilder
132
+ # Provides `render_component` method and namespace management
133
+ include ViewComponent::Form::Renderer
134
+
135
+ # Exposes a `validation_context` to your components
136
+ include ViewComponent::Form::ValidationContext
137
+
138
+ # All standard Rails form helpers
139
+ include ViewComponent::Form::Helpers::Rails
140
+
141
+ # Backports of Rails 7 form helpers (can be removed if you're running Rails >= 7)
142
+ # include ViewComponent::Form::Helpers::Rails7Backports
143
+
144
+ # Additional form helpers provided by ViewComponent::Form
145
+ # include ViewComponent::Form::Helpers::Custom
146
+
147
+ # Set the namespace you want to use for your own components
148
+ namespace "AnotherCustom::Form"
120
149
  end
121
150
  ```
122
151
 
@@ -6,7 +6,7 @@ module Vcf
6
6
  source_root File.join(File.dirname(__FILE__), "templates")
7
7
 
8
8
  class_option :namespace, default: "Form"
9
- class_option :path, default: "lib"
9
+ class_option :path, default: "app/helpers"
10
10
 
11
11
  def create_builder_from_template
12
12
  template "builder.rb.erb", destination
@@ -1,6 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class <%= class_name %> < ViewComponent::Form::Builder
4
+ # Instead of inheriting from ViewComponent::Form::Builder,
5
+ # you can also inherit from ActionView::Helpers::FormBuilder
6
+ # then include only the modules you need:
7
+
8
+ # Provides `render_component` method and namespace management
9
+ # include ViewComponent::Form::Renderer
10
+
11
+ # Exposes a `validation_context` to your components
12
+ # include ViewComponent::Form::ValidationContext
13
+
14
+ # All standard Rails form helpers
15
+ # include ViewComponent::Form::Helpers::Rails
16
+
17
+ # Backports of Rails 7 form helpers (can be removed if you're running Rails >= 7)
18
+ # include ViewComponent::Form::Helpers::Rails7Backports
19
+
20
+ # Additional form helpers provided by ViewComponent::Form
21
+ # include ViewComponent::Form::Helpers::Custom
22
+
4
23
  # Set the namespace you want to use for your own components
24
+ # requires inheriting from ViewComponent::Form::Builder
25
+ # or including ViewComponent::Form::Renderer
5
26
  namespace "<%= components_namespace %>"
6
27
  end
@@ -3,246 +3,11 @@
3
3
  module ViewComponent
4
4
  module Form
5
5
  class Builder < ActionView::Helpers::FormBuilder
6
- class Error < StandardError; end
7
-
8
- class NotImplementedComponentError < Error; end
9
-
10
- class NamespaceAlreadyAddedError < Error; end
11
-
12
- class_attribute :lookup_namespaces, default: [ViewComponent::Form]
13
-
14
- class << self
15
- def inherited(base)
16
- base.lookup_namespaces = lookup_namespaces.dup
17
-
18
- super
19
- end
20
-
21
- def namespace(namespace)
22
- if lookup_namespaces.include?(namespace)
23
- raise NamespaceAlreadyAddedError, "The component namespace '#{namespace}' is already added"
24
- end
25
-
26
- lookup_namespaces.prepend namespace
27
- end
28
- end
29
-
30
- attr_reader :validation_context
31
-
32
- def initialize(*)
33
- @__component_klass_cache = {}
34
-
35
- super
36
-
37
- @validation_context = options[:validation_context]
38
- end
39
-
40
- (field_helpers - %i[
41
- check_box
42
- datetime_field
43
- datetime_local_field
44
- fields
45
- fields_for
46
- file_field
47
- hidden_field
48
- label
49
- phone_field
50
- radio_button
51
- ]).each do |selector|
52
- class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
53
- def #{selector}(method, options = {}) # def text_field(method, options = {})
54
- render_component( # render_component(
55
- :#{selector}, # :text_field,
56
- @object_name, # @object_name,
57
- method, # method,
58
- objectify_options(options), # objectify_options(options),
59
- ) # )
60
- end # end
61
- RUBY_EVAL
62
- end
63
- alias phone_field telephone_field
64
-
65
- # See: https://github.com/rails/rails/blob/33d60cb02dcac26d037332410eabaeeb0bdc384c/actionview/lib/action_view/helpers/form_helper.rb#L2280
66
- def label(method, text = nil, options = {}, &block)
67
- render_component(:label, @object_name, method, text, objectify_options(options), &block)
68
- end
69
-
70
- def datetime_field(method, options = {})
71
- render_component(
72
- :datetime_local_field, @object_name, method, objectify_options(options)
73
- )
74
- end
75
- alias datetime_locale_field datetime_field
76
-
77
- def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
78
- render_component(
79
- :check_box, @object_name, method, checked_value, unchecked_value, objectify_options(options)
80
- )
81
- end
82
-
83
- def radio_button(method, tag_value, options = {})
84
- render_component(
85
- :radio_button, @object_name, method, tag_value, objectify_options(options)
86
- )
87
- end
88
-
89
- def file_field(method, options = {})
90
- self.multipart = true
91
- render_component(:file_field, @object_name, method, objectify_options(options))
92
- end
93
-
94
- def submit(value = nil, options = {})
95
- if value.is_a?(Hash)
96
- options = value
97
- value = nil
98
- end
99
- value ||= submit_default_value
100
- render_component(:submit, value, options)
101
- end
102
-
103
- def button(value = nil, options = {}, &block)
104
- if value.is_a?(Hash)
105
- options = value
106
- value = nil
107
- end
108
- value ||= submit_default_value
109
- render_component(:button, value, options, &block)
110
- end
111
-
112
- # See: https://github.com/rails/rails/blob/fe76a95b0d252a2d7c25e69498b720c96b243ea2/actionview/lib/action_view/helpers/form_options_helper.rb
113
- def select(method, choices = nil, options = {}, html_options = {}, &block)
114
- render_component(
115
- :select, @object_name, method, choices, objectify_options(options),
116
- @default_html_options.merge(html_options), &block
117
- )
118
- end
119
-
120
- # rubocop:disable Metrics/ParameterLists
121
- def collection_select(method, collection, value_method, text_method, options = {}, html_options = {})
122
- render_component(
123
- :collection_select, @object_name, method, collection, value_method, text_method,
124
- objectify_options(options), @default_html_options.merge(html_options)
125
- )
126
- end
127
-
128
- def grouped_collection_select(
129
- method, collection,
130
- group_method, group_label_method, option_key_method, option_value_method,
131
- options = {}, html_options = {}
132
- )
133
- render_component(
134
- :grouped_collection_select, @object_name, method, collection, group_method,
135
- group_label_method, option_key_method, option_value_method,
136
- objectify_options(options), @default_html_options.merge(html_options)
137
- )
138
- end
139
-
140
- def collection_check_boxes(method, collection, value_method, text_method, options = {}, html_options = {}, &block)
141
- render_component(
142
- :collection_check_boxes, @object_name, method, collection, value_method, text_method,
143
- objectify_options(options), @default_html_options.merge(html_options), &block
144
- )
145
- end
146
-
147
- def collection_radio_buttons(
148
- method, collection,
149
- value_method, text_method,
150
- options = {}, html_options = {},
151
- &block
152
- )
153
- render_component(
154
- :collection_radio_buttons, @object_name, method, collection, value_method, text_method,
155
- objectify_options(options), @default_html_options.merge(html_options), &block
156
- )
157
- end
158
- # rubocop:enable Metrics/ParameterLists
159
-
160
- def date_select(method, options = {}, html_options = {})
161
- render_component(
162
- :date_select, @object_name, method,
163
- objectify_options(options), @default_html_options.merge(html_options)
164
- )
165
- end
166
-
167
- def datetime_select(method, options = {}, html_options = {})
168
- render_component(
169
- :datetime_select, @object_name, method,
170
- objectify_options(options), @default_html_options.merge(html_options)
171
- )
172
- end
173
-
174
- def time_select(method, options = {}, html_options = {})
175
- render_component(
176
- :time_select, @object_name, method,
177
- objectify_options(options), @default_html_options.merge(html_options)
178
- )
179
- end
180
-
181
- def time_zone_select(method, priority_zones = nil, options = {}, html_options = {})
182
- render_component(
183
- :time_zone_select, @object_name, method, priority_zones,
184
- objectify_options(options), @default_html_options.merge(html_options)
185
- )
186
- end
187
-
188
- if defined?(ActionView::Helpers::Tags::ActionText)
189
- def rich_text_area(method, options = {})
190
- render_component(:rich_text_area, @object_name, method, objectify_options(options))
191
- end
192
- end
193
-
194
- def error_message(method, options = {})
195
- render_component(:error_message, @object_name, method, objectify_options(options))
196
- end
197
-
198
- def hint(method, text = nil, options = {}, &block)
199
- render_component(:hint, @object_name, method, text, objectify_options(options), &block)
200
- end
201
-
202
- # Backport field_id from Rails 7.0
203
- if Rails::VERSION::MAJOR < 7
204
- def field_id(method_name, *suffixes, namespace: @options[:namespace], index: @index)
205
- object_name = object_name.model_name.singular if object_name.respond_to?(:model_name)
206
-
207
- sanitized_object_name = object_name.to_s.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").delete_suffix("_")
208
-
209
- sanitized_method_name = method_name.to_s.delete_suffix("?")
210
-
211
- [
212
- namespace,
213
- sanitized_object_name.presence,
214
- (index unless sanitized_object_name.empty?),
215
- sanitized_method_name,
216
- *suffixes
217
- ].tap(&:compact!).join("_")
218
- end
219
- end
220
-
221
- private
222
-
223
- def render_component(component_name, *args, &block)
224
- component = component_klass(component_name).new(self, *args)
225
- component.render_in(@template, &block)
226
- end
227
-
228
- def objectify_options(options)
229
- @default_options.merge(options.merge(object: @object))
230
- end
231
-
232
- def component_klass(component_name)
233
- @__component_klass_cache[component_name] ||= begin
234
- component_klass = self.class.lookup_namespaces.filter_map do |namespace|
235
- "#{namespace}::#{component_name.to_s.camelize}Component".safe_constantize || false
236
- end.first
237
-
238
- unless component_klass.is_a?(Class) && component_klass < ViewComponent::Base
239
- raise NotImplementedComponentError, "Component named #{component_name} doesn't exist" \
240
- " or is not a ViewComponent::Base class"
241
- end
242
-
243
- component_klass
244
- end
245
- end
6
+ include ViewComponent::Form::Renderer
7
+ include ViewComponent::Form::ValidationContext
8
+ include ViewComponent::Form::Helpers::Rails
9
+ include ViewComponent::Form::Helpers::Rails7Backports if ::Rails::VERSION::MAJOR < 7
10
+ include ViewComponent::Form::Helpers::Custom
246
11
  end
247
12
  end
248
13
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ module Helpers
6
+ module Custom
7
+ def error_message(method, options = {})
8
+ render_component(:error_message, @object_name, method, objectify_options(options))
9
+ end
10
+
11
+ def hint(method, text = nil, options = {}, &block)
12
+ render_component(:hint, @object_name, method, text, objectify_options(options), &block)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,172 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ module Helpers
6
+ # rubocop:disable Metrics/ModuleLength
7
+ module Rails
8
+ # rubocop:disable Metrics/MethodLength
9
+ def self.included(base)
10
+ base.class_eval do
11
+ (field_helpers - %i[
12
+ check_box
13
+ datetime_field
14
+ datetime_local_field
15
+ fields
16
+ fields_for
17
+ file_field
18
+ hidden_field
19
+ label
20
+ phone_field
21
+ radio_button
22
+ ]).each do |selector|
23
+ class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
24
+ def #{selector}(method, options = {}) # def text_field(method, options = {})
25
+ render_component( # render_component(
26
+ :#{selector}, # :text_field,
27
+ @object_name, # @object_name,
28
+ method, # method,
29
+ objectify_options(options), # objectify_options(options),
30
+ ) # )
31
+ end # end
32
+ RUBY_EVAL
33
+ end
34
+ alias_method :phone_field, :telephone_field
35
+ end
36
+ end
37
+ # rubocop:enable Metrics/MethodLength
38
+
39
+ # See: https://github.com/rails/rails/blob/33d60cb02dcac26d037332410eabaeeb0bdc384c/actionview/lib/action_view/helpers/form_helper.rb#L2280
40
+ def label(method, text = nil, options = {}, &block)
41
+ render_component(:label, @object_name, method, text, objectify_options(options), &block)
42
+ end
43
+
44
+ def datetime_field(method, options = {})
45
+ render_component(
46
+ :datetime_local_field, @object_name, method, objectify_options(options)
47
+ )
48
+ end
49
+ alias datetime_locale_field datetime_field
50
+
51
+ def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
52
+ render_component(
53
+ :check_box, @object_name, method, checked_value, unchecked_value, objectify_options(options)
54
+ )
55
+ end
56
+
57
+ def radio_button(method, tag_value, options = {})
58
+ render_component(
59
+ :radio_button, @object_name, method, tag_value, objectify_options(options)
60
+ )
61
+ end
62
+
63
+ def file_field(method, options = {})
64
+ self.multipart = true
65
+ render_component(:file_field, @object_name, method, objectify_options(options))
66
+ end
67
+
68
+ def submit(value = nil, options = {})
69
+ if value.is_a?(Hash)
70
+ options = value
71
+ value = nil
72
+ end
73
+ value ||= submit_default_value
74
+ render_component(:submit, value, options)
75
+ end
76
+
77
+ def button(value = nil, options = {}, &block)
78
+ if value.is_a?(Hash)
79
+ options = value
80
+ value = nil
81
+ end
82
+ value ||= submit_default_value
83
+ render_component(:button, value, options, &block)
84
+ end
85
+
86
+ # See: https://github.com/rails/rails/blob/fe76a95b0d252a2d7c25e69498b720c96b243ea2/actionview/lib/action_view/helpers/form_options_helper.rb
87
+ def select(method, choices = nil, options = {}, html_options = {}, &block)
88
+ render_component(
89
+ :select, @object_name, method, choices, objectify_options(options),
90
+ @default_html_options.merge(html_options), &block
91
+ )
92
+ end
93
+
94
+ # rubocop:disable Metrics/ParameterLists
95
+ def collection_select(method, collection, value_method, text_method, options = {}, html_options = {})
96
+ render_component(
97
+ :collection_select, @object_name, method, collection, value_method, text_method,
98
+ objectify_options(options), @default_html_options.merge(html_options)
99
+ )
100
+ end
101
+
102
+ def grouped_collection_select(
103
+ method, collection,
104
+ group_method, group_label_method, option_key_method, option_value_method,
105
+ options = {}, html_options = {}
106
+ )
107
+ render_component(
108
+ :grouped_collection_select, @object_name, method, collection, group_method,
109
+ group_label_method, option_key_method, option_value_method,
110
+ objectify_options(options), @default_html_options.merge(html_options)
111
+ )
112
+ end
113
+
114
+ def collection_check_boxes(method, collection, value_method, text_method, options = {}, html_options = {},
115
+ &block)
116
+ render_component(
117
+ :collection_check_boxes, @object_name, method, collection, value_method, text_method,
118
+ objectify_options(options), @default_html_options.merge(html_options), &block
119
+ )
120
+ end
121
+
122
+ def collection_radio_buttons(
123
+ method, collection,
124
+ value_method, text_method,
125
+ options = {}, html_options = {},
126
+ &block
127
+ )
128
+ render_component(
129
+ :collection_radio_buttons, @object_name, method, collection, value_method, text_method,
130
+ objectify_options(options), @default_html_options.merge(html_options), &block
131
+ )
132
+ end
133
+ # rubocop:enable Metrics/ParameterLists
134
+
135
+ def date_select(method, options = {}, html_options = {})
136
+ render_component(
137
+ :date_select, @object_name, method,
138
+ objectify_options(options), @default_html_options.merge(html_options)
139
+ )
140
+ end
141
+
142
+ def datetime_select(method, options = {}, html_options = {})
143
+ render_component(
144
+ :datetime_select, @object_name, method,
145
+ objectify_options(options), @default_html_options.merge(html_options)
146
+ )
147
+ end
148
+
149
+ def time_select(method, options = {}, html_options = {})
150
+ render_component(
151
+ :time_select, @object_name, method,
152
+ objectify_options(options), @default_html_options.merge(html_options)
153
+ )
154
+ end
155
+
156
+ def time_zone_select(method, priority_zones = nil, options = {}, html_options = {})
157
+ render_component(
158
+ :time_zone_select, @object_name, method, priority_zones,
159
+ objectify_options(options), @default_html_options.merge(html_options)
160
+ )
161
+ end
162
+
163
+ if defined?(ActionView::Helpers::Tags::ActionText)
164
+ def rich_text_area(method, options = {})
165
+ render_component(:rich_text_area, @object_name, method, objectify_options(options))
166
+ end
167
+ end
168
+ end
169
+ # rubocop:enable Metrics/ModuleLength
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ module Helpers
6
+ module Rails7Backports
7
+ def field_id(method_name, *suffixes, namespace: @options[:namespace], index: @index)
8
+ object_name = object_name.model_name.singular if object_name.respond_to?(:model_name)
9
+
10
+ sanitized_object_name = object_name.to_s.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").delete_suffix("_")
11
+
12
+ sanitized_method_name = method_name.to_s.delete_suffix("?")
13
+
14
+ [
15
+ namespace,
16
+ sanitized_object_name.presence,
17
+ (index unless sanitized_object_name.empty?),
18
+ sanitized_method_name,
19
+ *suffixes
20
+ ].tap(&:compact!).join("_")
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ module Renderer
6
+ class Error < StandardError; end
7
+ class NamespaceAlreadyAddedError < Error; end
8
+ class NotImplementedComponentError < Error; end
9
+
10
+ # rubocop:disable Metrics/MethodLength
11
+ def self.included(base)
12
+ base.class_eval do
13
+ original_initialize_method = instance_method(:initialize)
14
+
15
+ define_method(:initialize) do |*args, &block|
16
+ @__component_klass_cache = {}
17
+
18
+ original_initialize_method.bind_call(self, *args, &block)
19
+ end
20
+
21
+ class_attribute :lookup_namespaces, default: [ViewComponent::Form]
22
+
23
+ class << self
24
+ def inherited(base)
25
+ base.lookup_namespaces = lookup_namespaces.dup
26
+
27
+ super
28
+ end
29
+
30
+ def namespace(namespace)
31
+ if lookup_namespaces.include?(namespace)
32
+ raise NamespaceAlreadyAddedError, "The component namespace '#{namespace}' is already added"
33
+ end
34
+
35
+ lookup_namespaces.prepend namespace
36
+ end
37
+ end
38
+ end
39
+ end
40
+ # rubocop:enable Metrics/MethodLength
41
+
42
+ private
43
+
44
+ def render_component(component_name, *args, &block)
45
+ component = component_klass(component_name).new(self, *args)
46
+ component.render_in(@template, &block)
47
+ end
48
+
49
+ def objectify_options(options)
50
+ @default_options.merge(options.merge(object: @object))
51
+ end
52
+
53
+ def component_klass(component_name)
54
+ @__component_klass_cache[component_name] ||= begin
55
+ component_klass = self.class.lookup_namespaces.filter_map do |namespace|
56
+ "#{namespace}::#{component_name.to_s.camelize}Component".safe_constantize || false
57
+ end.first
58
+
59
+ unless component_klass.is_a?(Class) && component_klass < ViewComponent::Base
60
+ raise NotImplementedComponentError, "Component named #{component_name} doesn't exist " \
61
+ "or is not a ViewComponent::Base class"
62
+ end
63
+
64
+ component_klass
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ module ValidationContext
6
+ attr_reader :validation_context
7
+
8
+ def self.included(base)
9
+ base.class_eval do
10
+ original_initialize_method = instance_method(:initialize)
11
+
12
+ define_method(:initialize) do |*args, &block|
13
+ original_initialize_method.bind_call(self, *args, &block)
14
+
15
+ @validation_context = options[:validation_context]
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ViewComponent
4
4
  module Form
5
- VERSION = "0.2.4"
5
+ VERSION = "0.2.5"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: view_component-form
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pantographe
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-04-27 00:00:00.000000000 Z
11
+ date: 2023-05-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionview
@@ -59,7 +59,7 @@ dependencies:
59
59
  version: 2.34.0
60
60
  - - "<"
61
61
  - !ruby/object:Gem::Version
62
- version: '3.0'
62
+ version: '4.0'
63
63
  type: :runtime
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
@@ -69,7 +69,7 @@ dependencies:
69
69
  version: 2.34.0
70
70
  - - "<"
71
71
  - !ruby/object:Gem::Version
72
- version: '3.0'
72
+ version: '4.0'
73
73
  - !ruby/object:Gem::Dependency
74
74
  name: zeitwerk
75
75
  requirement: !ruby/object:Gem::Requirement
@@ -136,7 +136,12 @@ files:
136
136
  - lib/view_component/form/builder.rb
137
137
  - lib/view_component/form/class_names_helper.rb
138
138
  - lib/view_component/form/engine.rb
139
+ - lib/view_component/form/helpers/custom.rb
140
+ - lib/view_component/form/helpers/rails.rb
141
+ - lib/view_component/form/helpers/rails_7_backports.rb
142
+ - lib/view_component/form/renderer.rb
139
143
  - lib/view_component/form/test_helpers.rb
144
+ - lib/view_component/form/validation_context.rb
140
145
  - lib/view_component/form/version.rb
141
146
  homepage: https://github.com/pantographe/view_component-form
142
147
  licenses:
@@ -162,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
162
167
  - !ruby/object:Gem::Version
163
168
  version: '0'
164
169
  requirements: []
165
- rubygems_version: 3.3.12
170
+ rubygems_version: 3.3.26
166
171
  signing_key:
167
172
  specification_version: 4
168
173
  summary: Rails FormBuilder for ViewComponent