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 +4 -4
- data/CHANGELOG.md +14 -1
- data/README.md +127 -126
- data/app/components/view_component/form/base_component.rb +1 -1
- data/lib/view_component/form/configuration.rb +20 -0
- data/lib/view_component/form/helpers/rails.rb +1 -1
- data/lib/view_component/form/renderer.rb +3 -3
- data/lib/view_component/form/version.rb +1 -1
- data/lib/view_component/form.rb +9 -0
- metadata +9 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f44ea4d5228e0e3e42b68bac848d7806d73097cbbca8b27758d5f55b11ab0a94
|
4
|
+
data.tar.gz: 1fa7588808ca2371b6b82679747292b22f3ba126ead0e870906d8ccbeef3845d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
|
-
|
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
|
-
|
15
|
-
-
|
14
|
+
|
15
|
+
- Rails 6.1+ (with or without ActionText)
|
16
|
+
- Ruby 3.0+
|
16
17
|
|
17
18
|
## Installation
|
18
19
|
|
19
|
-
|
20
|
+
```shell
|
21
|
+
bundle add view_component-form
|
22
|
+
```
|
23
|
+
|
24
|
+
### Configuration
|
20
25
|
|
21
26
|
```ruby
|
22
|
-
|
27
|
+
# config/initializers/vcf.rb
|
28
|
+
|
29
|
+
ViewComponent::Form.configure do |config|
|
30
|
+
config.parent_component = 'ApplicationFormComponent'
|
31
|
+
end
|
23
32
|
```
|
24
33
|
|
25
|
-
|
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
|
-
|
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
|
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:
|
73
|
+
+ <%= form_for @user, builder: FormBuilder do |f| %>
|
36
74
|
```
|
37
75
|
|
38
|
-
|
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
|
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
|
-
|
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
|
-
|
112
|
+
The `ViewComponent::Form::Builder` will use the provided `namespace` to find any components you've customized.
|
102
113
|
|
103
|
-
```
|
104
|
-
# app/helpers/
|
105
|
-
class
|
106
|
-
|
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
|
-
|
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
|
-
```
|
120
|
-
|
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
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
143
|
+
Add the helper method to your `ViewComponent::Form::Builder`
|
172
144
|
|
173
145
|
```rb
|
174
|
-
# app/
|
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
|
-
|
177
|
-
|
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
|
-
|
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
|
-
|
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
|
-
```
|
190
|
-
|
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
|
-
|
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
|
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
|
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
|
-
|
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.
|
@@ -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
|
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 =
|
56
|
-
|
57
|
-
end.
|
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 " \
|
data/lib/view_component/form.rb
CHANGED
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
|
+
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:
|
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.
|
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.
|
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.
|
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.
|
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:
|
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.
|
172
|
+
rubygems_version: 3.5.14
|
172
173
|
signing_key:
|
173
174
|
specification_version: 4
|
174
175
|
summary: Rails FormBuilder for ViewComponent
|