view_component-form 0.2.6 → 0.2.7

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: 128d4c769f1fa3e25cf83830db0b8279413dd8da3e9c7e312aeee06f0456336a
4
- data.tar.gz: 63d592e4fa33d6bb77262bea0526761d5b251f26f37c6fac42a771f2506b3250
3
+ metadata.gz: f44ea4d5228e0e3e42b68bac848d7806d73097cbbca8b27758d5f55b11ab0a94
4
+ data.tar.gz: 1fa7588808ca2371b6b82679747292b22f3ba126ead0e870906d8ccbeef3845d
5
5
  SHA512:
6
- metadata.gz: f584160cf5560bf80869e4b98ea86d4ac0ce35b25c97dcbb5f38d4fbbacddfce7c64734697327d500b36e537391ac5c34f81470491b2ed75a3347e6664b53b08
7
- data.tar.gz: 9fd72c0345d99a0207c006d916cf7e4f75224a88b4bc0175d3f56ffad491ebc42da14efa3619796896c12d37a8eef88dbd70911f47700eaa5fe520ea9f1277e0
6
+ metadata.gz: 36cf6c62ac032457150a59a4a1e1e8208752e01a44b3372b87b9ef4c8573523159cd34337fd784fb733fba89b0ad871883e569d0f141b115c18c6fcbc95245da
7
+ data.tar.gz: 985112bbfc1157644a3213b08fe4f4ca0375d5c76b0f58c4670083b8751a2134280a9e50fc50a4886320d61bdca227f207deac779de37b2fc58dd3cc86927a9b
data/CHANGELOG.md CHANGED
@@ -5,6 +5,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
+ Nothing yet
9
+
10
+ ## [0.2.7] - 2024-07-18
11
+ ### Added
12
+ - Added parent_component configuration for field components (#160)
13
+ - Added Ruby 3.3 support (#164)
14
+ - Add `lookup_chain` customizability (#162)
15
+
16
+ ### Removed
17
+ - Drop Ruby 2.7 support (#164)
18
+ - Drop Rails 6.0 support (#164)
8
19
 
9
20
  ## [0.2.6] - 2023-10-11
10
21
  ### Added
@@ -103,7 +114,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
103
114
  - Add CHANGELOG (#50)
104
115
  - Add CI (#2)
105
116
 
106
- [Unreleased]: https://github.com/pantographe/view_component-form/compare/v0.2.5...HEAD
117
+ [Unreleased]: https://github.com/pantographe/view_component-form/compare/v0.2.7...HEAD
118
+ [0.2.7]: https://github.com/pantographe/view_component-form/compare/v0.2.6...v0.2.7
119
+ [0.2.6]: https://github.com/pantographe/view_component-form/compare/v0.2.5...v0.2.6
107
120
  [0.2.5]: https://github.com/pantographe/view_component-form/compare/v0.2.4...v0.2.5
108
121
  [0.2.4]: https://github.com/pantographe/view_component-form/compare/v0.2.3...v0.2.4
109
122
  [0.2.3]: https://github.com/pantographe/view_component-form/compare/v0.2.2...v0.2.3
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # ViewComponent::Form
2
2
 
3
- **ViewComponent::Form** provides a `FormBuilder` with the same interface as [`ActionView::Helpers::FormBuilder`](https://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html), but using [ViewComponent](https://github.com/github/view_component)s for rendering the fields. It's a starting point for writing your own custom ViewComponents.
4
-
5
- :warning: **This is an early release: the API is subject to change until we reach `v1.0.0`.**
3
+ **`ViewComponent::Form`** is a customizable form builder using the same interface as [`ActionView::Helpers::FormBuilder`](https://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html) but with extensible [ViewComponent](https://github.com/github/view_component) components.
6
4
 
7
5
  Development of this gem is sponsored by:
8
6
 
@@ -10,34 +8,81 @@ Development of this gem is sponsored by:
10
8
 
11
9
  ## Compatibility
12
10
 
11
+ > [!WARNING] > **This is an early release, and the API is subject to change until `v1.0.0`.**
12
+
13
13
  This gem is tested on:
14
- - Rails 6.0+ (with or without ActionText)
15
- - Ruby 2.7+
14
+
15
+ - Rails 6.1+ (with or without ActionText)
16
+ - Ruby 3.0+
16
17
 
17
18
  ## Installation
18
19
 
19
- Add this line to your application's Gemfile:
20
+ ```shell
21
+ bundle add view_component-form
22
+ ```
23
+
24
+ ### Configuration
20
25
 
21
26
  ```ruby
22
- gem 'view_component-form'
27
+ # config/initializers/vcf.rb
28
+
29
+ ViewComponent::Form.configure do |config|
30
+ config.parent_component = 'ApplicationFormComponent'
31
+ end
23
32
  ```
24
33
 
25
- And then execute:
34
+ | Attribute | Purpose | Default |
35
+ | --------------------------- | ----------------------------------------------------- | ----------------------- |
36
+ | `parent_component` (string) | Parent class for all `ViewComponent::Form` components | `"ViewComponent::Base"` |
37
+
38
+ #### Configuring component lookup
39
+
40
+ `ViewComponent::Form` will automatically infer the component class with a `Component` suffix. You can customize the lookup using the `lookup_chain`:
41
+
42
+ ```rb
43
+ # config/initializers/vcf.rb
44
+
45
+ ViewComponent::Form.configure do |config|
46
+ without_component_suffix = lambda do |component_name, namespaces: []|
47
+ namespaces.lazy.map do |namespace|
48
+ "#{namespace}::#{component_name.to_s.camelize}".safe_constantize
49
+ end.find(&:itself)
50
+ end
51
+
52
+ config.lookup_chain.prepend(without_component_suffix)
53
+ end
54
+ ```
26
55
 
27
- $ bundle install
56
+ `ViewComponent::Form` will iterate through the `lookup_chain` until a value is returned. By using `prepend` we can fallback on the default `ViewComponent::Form` lookup.
28
57
 
29
58
  ## Usage
30
59
 
31
- Add a `builder` param to your `form_for`, `form_with`, `fields_for` or `fields`:
60
+ Add your own form builder.
61
+
62
+ ```shell
63
+ bin/rails generate vcf:builder FormBuilder
64
+ create app/helpers/form_builder.rb
65
+ ```
66
+
67
+ To use the form builder:
68
+
69
+ - add a `builder` param to your `form_for`, `form_with`, `fields_for` or `fields`:
32
70
 
33
71
  ```diff
34
72
  - <%= form_for @user do |f| %>
35
- + <%= form_for @user, builder: ViewComponent::Form::Builder do |f| %>
73
+ + <%= form_for @user, builder: FormBuilder do |f| %>
36
74
  ```
37
75
 
38
- You can also define a default FormBuilder at the controller level using [default_form_builder](https://api.rubyonrails.org/classes/ActionController/FormBuilder.html#method-i-default_form_builder).
76
+ - or; set it as a default in your controller using [default_form_builder](https://api.rubyonrails.org/classes/ActionController/FormBuilder.html#method-i-default_form_builder).
77
+
78
+ ```ruby
79
+ # app/controllers/application_controller.rb
80
+ class ApplicationController < ActionController::Base
81
+ default_form_builder FormBuilder
82
+ end
83
+ ```
39
84
 
40
- Then call your helpers as usual:
85
+ Then use ActionView form builder helpers as you would normally:
41
86
 
42
87
  ```erb
43
88
  <%# app/views/users/_form.html.erb %>
@@ -62,141 +107,67 @@ Then call your helpers as usual:
62
107
  <% end %>
63
108
  ```
64
109
 
65
- It should work out of the box, but does nothing particularly interesting for now.
66
-
67
- ```html
68
- <form class="edit_user" id="edit_user_1" action="/users/1" accept-charset="UTF-8" method="post">
69
- <input type="hidden" name="_method" value="patch" />
70
- <input type="hidden" name="authenticity_token" value="[...]" />
71
-
72
- <label for="user_first_name">First name</label>
73
- <input type="text" value="John" name="user[first_name]" id="user_first_name" />
74
-
75
- <label for="user_last_name">Last name</label>
76
- <input type="text" value="Doe" name="user[last_name]" id="user_last_name" />
77
-
78
- <label for="user_email">E-mail</label>
79
- <input type="email" value="john.doe@example.com" name="user[email]" id="user_email" />
80
-
81
- <label for="user_password">Password</label>
82
- <input type="password" name="user[password]" id="user_password" aria-describedby="user_password_description" />
83
- <div id="user_password_description">
84
- <div>The password should be at least 8 characters long</div>
85
- </div>
86
- </form>
87
- ```
88
-
89
- The `ViewComponent::Form::*` components are included in the gem.
90
-
91
- ### Customizing the `FormBuilder` and the components
92
-
93
- First, generate your own `FormBuilder`:
94
-
95
- ```console
96
- bin/rails generate vcf:builder CustomFormBuilder
97
-
98
- create app/helpers/custom_form_builder.rb
99
- ```
110
+ ### Customizing built-in components
100
111
 
101
- This allows you to pick the namespace your components will be loaded from.
112
+ The `ViewComponent::Form::Builder` will use the provided `namespace` to find any components you've customized.
102
113
 
103
- ```rb
104
- # app/helpers/custom_form_builder.rb
105
- class CustomFormBuilder < ViewComponent::Form::Builder
106
- # Set the namespace you want to use for your own components
107
- namespace "Custom::Form"
114
+ ```ruby
115
+ # app/helpers/form_builder.rb
116
+ class FormBuilder < ViewComponent::Form::Builder
117
+ namespace Form
108
118
  end
109
119
  ```
110
120
 
111
- Use the generator options to change the default namespace or the path where the file will be created:
112
-
113
- ```console
114
- bin/rails generate vcf:builder AnotherCustomFormBuilder --namespace AnotherCustom::Form --path app/forms
115
-
116
- create app/forms/another_custom_form_builder.rb
117
- ```
121
+ Let's customize the `text_field` helper by generating a new [ViewComponent](https://github.com/github/view_component) in the namespace defined within the builder.
118
122
 
119
- ```rb
120
- # app/forms/another_custom_form_builder.rb
121
- class AnotherCustomFormBuilder < ViewComponent::Form::Builder
122
- # Set the namespace you want to use for your own components
123
- namespace "AnotherCustom::Form"
124
- end
123
+ ```shell
124
+ bin/rails generate component Form::TextField --parent ViewComponent::Form::TextFieldComponent --inline
125
125
  ```
126
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"
127
+ ```ruby
128
+ # app/components/form/text_field_component.rb
129
+ class Form::TextFieldComponent < ViewComponent::Form::TextFieldComponent
130
+ def html_class
131
+ class_names("custom-text-field", "has-error": method_errors?)
132
+ end
149
133
  end
150
134
  ```
151
135
 
152
- Now let's generate your own components to customize their rendering. We can use the standard view_component generator:
153
-
154
- ```console
155
- bin/rails generate component Custom::Form::TextField --inline --parent ViewComponent::Form::TextFieldComponent
156
-
157
- invoke test_unit
158
- create test/components/custom/form/text_field_component_test.rb
159
- create app/components/custom/form/text_field_component.rb
160
- ```
161
-
162
- :warning: The `--parent` option is available since ViewComponent [`v2.41.0`](https://viewcomponent.org/CHANGELOG.html#2410). If you're using a previous version, you can always edit the generated `Custom::Form::CustomTextFieldComponent` class to make it inherit from `ViewComponent::Form::TextFieldComponent`.
136
+ In this case we're leveraging the [`#class_names`](https://api.rubyonrails.org/classes/ActionView/Helpers/TagHelper.html#method-i-class_names) helper to:
163
137
 
164
- Change your forms to use your new builder:
138
+ - always add the `custom-text-field` class;
139
+ - add the `has-error` class if there is an error on the attribute (using `ViewComponent::Form::FieldComponent#method_errors?`).
165
140
 
166
- ```diff
167
- - <%= form_for @user, builder: ViewComponent::Form::Builder do |f| %>
168
- + <%= form_for @user, builder: CustomFormBuilder do |f| %>
169
- ```
141
+ ### Adding your own custom helpers and components
170
142
 
171
- You can then customize the behavior of your `Custom::Form::CustomTextFieldComponent`:
143
+ Add the helper method to your `ViewComponent::Form::Builder`
172
144
 
173
145
  ```rb
174
- # app/components/custom/form/text_field_component.rb
146
+ # app/helpers/form_builder.rb
147
+ class FormBuilder < ViewComponent::Form::Builder
148
+ def year_field(method, options = {})
149
+ render_component(:year_field, @object_name, method, objectify_options(options))
150
+ end
175
151
 
176
- class Admin::Form::TextFieldComponent < ViewComponent::Form::TextFieldComponent
177
- def html_class
178
- class_names("custom-text-field", "has-error": method_errors?)
152
+ def money_field(method, currencies = [], options = {})
153
+ render_component(:money_field, @object_name, method, currencies, objectify_options(options))
179
154
  end
180
155
  end
181
156
  ```
182
157
 
183
- In this case we leverage the [`#class_names`](https://api.rubyonrails.org/classes/ActionView/Helpers/TagHelper.html#method-i-class_names) helper to:
184
- - always add the `custom-text-field` class;
185
- - add the `has-error` class if there is an error on the attribute (using `ViewComponent::Form::FieldComponent#method_errors?`).
158
+ Add your component which can optionally inherit from:
186
159
 
187
- The rendered form field will now look like this:
160
+ - `ViewComponent::Form::FieldComponent` (suggested when adding a field because of helpers)
161
+ - `ViewComponent::Form::BaseComponent`
162
+ - or any of the `ViewComponent::Form::*Component` such as `ViewComponent::Form::TextFieldComponent`
188
163
 
189
- ```html
190
- <input class="custom-text-field" type="text" value="John" name="user[first_name]" id="user_first_name">
164
+ ```rb
165
+ # app/components/form/year_field_component.rb
166
+ class Form::YearFieldComponent < ViewComponent::Form::FieldComponent # or ViewComponent::Form::BaseComponent
167
+ end
191
168
  ```
192
169
 
193
- You can use the same approach to inject options, wrap the input in a `<div>`, etc.
194
-
195
- We'll add more use cases to the documentation soon.
196
-
197
- ### Building your own components
198
-
199
- When building your own ViewComponents for using in forms, it's recommended to inherit from `ViewComponent::Form::FieldComponent`, so you get access to the following helpers:
170
+ When inheriting from `ViewComponent::Form::FieldComponent`, you get access to the following helpers:
200
171
 
201
172
  #### `#label_text`
202
173
 
@@ -239,16 +210,27 @@ en:
239
210
  Renders:
240
211
 
241
212
  ```html
242
- <form class="edit_user" id="edit_user_1" action="/users/1" accept-charset="UTF-8" method="post">
213
+ <form
214
+ class="edit_user"
215
+ id="edit_user_1"
216
+ action="/users/1"
217
+ accept-charset="UTF-8"
218
+ method="post"
219
+ >
243
220
  <!-- ... -->
244
221
  <label>
245
222
  Your first name<br />
246
- <input type="text" value="John" name="user[first_name]" id="user_first_name" />
223
+ <input
224
+ type="text"
225
+ value="John"
226
+ name="user[first_name]"
227
+ id="user_first_name"
228
+ />
247
229
  </label>
248
230
  </form>
249
231
  ```
250
232
 
251
- #### Validations
233
+ ### Validations
252
234
 
253
235
  Let's consider the following model for the examples below.
254
236
 
@@ -339,6 +321,25 @@ def length_validator
339
321
  end
340
322
  ```
341
323
 
324
+ ### Setting up your own base component class
325
+
326
+ 1. Setup some base component from which the form components will inherit from
327
+
328
+ ```rb
329
+ class ApplicationFormComponent < ViewComponent::Base
330
+ end
331
+ ```
332
+
333
+ 2. Configure the parent component class
334
+
335
+ ```rb
336
+ # config/initializers/vcf.rb
337
+
338
+ ViewComponent::Form.configure do |config|
339
+ config.parent_component = 'ApplicationFormComponent'
340
+ end
341
+ ```
342
+
342
343
  ### Using your form components without a backing model
343
344
 
344
345
  If you want to ensure that your fields display consistently across your app, you'll need to lean on Rails' own helpers. You may be used to using form tag helpers such as `text_field_tag` to generate tags, or even writing out plain HTML tags. These can't be integrated with a form builder, so they won't offer you the benefits of this gem.
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ViewComponent
4
4
  module Form
5
- class BaseComponent < ViewComponent::Base
5
+ class BaseComponent < ViewComponent::Form.configuration.parent_component.constantize
6
6
  class << self
7
7
  attr_accessor :default_options
8
8
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ class Configuration
6
+ attr_accessor :parent_component, :lookup_chain
7
+
8
+ def initialize
9
+ @parent_component = "ViewComponent::Base"
10
+ @lookup_chain = [
11
+ lambda do |component_name, namespaces: []|
12
+ namespaces.lazy.map do |namespace|
13
+ "#{namespace}::#{component_name.to_s.camelize}Component".safe_constantize
14
+ end.find(&:itself)
15
+ end
16
+ ]
17
+ end
18
+ end
19
+ end
20
+ end
@@ -46,7 +46,7 @@ module ViewComponent
46
46
  :datetime_local_field, @object_name, method, objectify_options(options)
47
47
  )
48
48
  end
49
- alias datetime_locale_field datetime_field
49
+ alias datetime_local_field datetime_field
50
50
 
51
51
  def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
52
52
  render_component(
@@ -52,9 +52,9 @@ module ViewComponent
52
52
 
53
53
  def component_klass(component_name)
54
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
55
+ component_klass = ViewComponent::Form.configuration.lookup_chain.lazy.map do |lookup|
56
+ lookup.call(component_name, namespaces: lookup_namespaces)
57
+ end.find(&:itself)
58
58
 
59
59
  unless component_klass.is_a?(Class) && component_klass < ViewComponent::Base
60
60
  raise NotImplementedComponentError, "Component named #{component_name} doesn't exist " \
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ViewComponent
4
4
  module Form
5
- VERSION = "0.2.6"
5
+ VERSION = "0.2.7"
6
6
  end
7
7
  end
@@ -5,6 +5,15 @@ require "zeitwerk"
5
5
 
6
6
  module ViewComponent
7
7
  module Form
8
+ class << self
9
+ def configuration
10
+ @configuration ||= Configuration.new
11
+ end
12
+
13
+ def configure
14
+ yield configuration
15
+ end
16
+ end
8
17
  end
9
18
  end
10
19
 
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.6
4
+ version: 0.2.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pantographe
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-10-11 00:00:00.000000000 Z
11
+ date: 2024-07-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionview
@@ -16,7 +16,7 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 6.0.0
19
+ version: 6.1.0
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
22
  version: '7.2'
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: 6.0.0
29
+ version: 6.1.0
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '7.2'
@@ -36,7 +36,7 @@ dependencies:
36
36
  requirements:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: 6.0.0
39
+ version: 6.1.0
40
40
  - - "<"
41
41
  - !ruby/object:Gem::Version
42
42
  version: '7.2'
@@ -46,7 +46,7 @@ dependencies:
46
46
  requirements:
47
47
  - - ">="
48
48
  - !ruby/object:Gem::Version
49
- version: 6.0.0
49
+ version: 6.1.0
50
50
  - - "<"
51
51
  - !ruby/object:Gem::Version
52
52
  version: '7.2'
@@ -136,6 +136,7 @@ files:
136
136
  - lib/view_component/form.rb
137
137
  - lib/view_component/form/builder.rb
138
138
  - lib/view_component/form/class_names_helper.rb
139
+ - lib/view_component/form/configuration.rb
139
140
  - lib/view_component/form/engine.rb
140
141
  - lib/view_component/form/helpers/custom.rb
141
142
  - lib/view_component/form/helpers/rails.rb
@@ -161,14 +162,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
161
162
  requirements:
162
163
  - - ">="
163
164
  - !ruby/object:Gem::Version
164
- version: 2.7.0
165
+ version: 3.0.0
165
166
  required_rubygems_version: !ruby/object:Gem::Requirement
166
167
  requirements:
167
168
  - - ">="
168
169
  - !ruby/object:Gem::Version
169
170
  version: '0'
170
171
  requirements: []
171
- rubygems_version: 3.4.10
172
+ rubygems_version: 3.5.14
172
173
  signing_key:
173
174
  specification_version: 4
174
175
  summary: Rails FormBuilder for ViewComponent