view_component-form 0.2.4 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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