view_component 2.23.0 → 2.25.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of view_component might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +47 -1
- data/lib/rails/generators/component/component_generator.rb +7 -0
- data/lib/rails/generators/component/templates/component.rb.tt +6 -0
- data/lib/rails/generators/erb/component_generator.rb +7 -4
- data/lib/rails/generators/preview/component_generator.rb +21 -0
- data/lib/rails/generators/preview/templates/component_preview.rb.tt +5 -0
- data/lib/view_component/base.rb +28 -1
- data/lib/view_component/collection.rb +8 -5
- data/lib/view_component/compiler.rb +8 -6
- data/lib/view_component/slot_v2.rb +19 -11
- data/lib/view_component/version.rb +2 -2
- metadata +9 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c411f9f34b25054093f7abe23c5842c7523f083ecdb1ba586429545548eca423
|
4
|
+
data.tar.gz: 744c27c0907544dfb93eb37ecf47c74dd7df86855c0e2b91f9619a77bd8eefc8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bee62ecbcfecbc53146b8a8e55207baf2d14769adda2bb2349494a82224acf12fa6584bfc32512e96474f28f011823f2c5712cbc021773d439c43fab8b090503
|
7
|
+
data.tar.gz: 3f519b85b066d89fdf75afb17563cb868bb4fb673caa21326661f0738b9b4398af068421064ca6f77abf08b7b46bdc549c132252b111b8fb3009809d430b9682
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,52 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
-
##
|
3
|
+
## main
|
4
|
+
|
5
|
+
## 2.25.1
|
6
|
+
|
7
|
+
* Experimental: call `._after_compile` class method after a component is compiled.
|
8
|
+
|
9
|
+
*Joel Hawksley*
|
10
|
+
|
11
|
+
* Fix bug where SlotV2 was rendered as an HTML string when using Slim.
|
12
|
+
|
13
|
+
*Manuel Puyol*
|
14
|
+
|
15
|
+
## 2.25.0
|
16
|
+
|
17
|
+
* Add `--preview` generator option to create an associated preview file.
|
18
|
+
|
19
|
+
*Bob Maerten*
|
20
|
+
|
21
|
+
* Add argument validation to avoid `content` override.
|
22
|
+
|
23
|
+
*Manuel Puyol*
|
24
|
+
|
25
|
+
## 2.24.0
|
26
|
+
|
27
|
+
* Add `--inline` option to the erb generator. Prevents default erb template from being created and creates a component with a call method.
|
28
|
+
|
29
|
+
*Nachiket Pusalkar*
|
30
|
+
|
31
|
+
* Add test case for checking presence of `content` in `#render?`.
|
32
|
+
|
33
|
+
*Joel Hawksley*
|
34
|
+
|
35
|
+
* Rename `master` branch to `main`.
|
36
|
+
|
37
|
+
*Joel Hawksley*
|
38
|
+
|
39
|
+
## 2.23.2
|
40
|
+
|
41
|
+
* Fix bug where rendering a component `with_collection` from a controller raised an error.
|
42
|
+
|
43
|
+
*Joel Hawksley*
|
44
|
+
|
45
|
+
## 2.23.1
|
46
|
+
|
47
|
+
* Fixed out-of-order rendering bug in `ActionView::SlotableV2`
|
48
|
+
|
49
|
+
*Blake Williams*
|
4
50
|
|
5
51
|
## 2.23.0
|
6
52
|
|
@@ -7,6 +7,7 @@ module Rails
|
|
7
7
|
|
8
8
|
argument :attributes, type: :array, default: [], banner: "attribute"
|
9
9
|
check_class_collision suffix: "Component"
|
10
|
+
class_option :inline, type: :boolean, default: false
|
10
11
|
|
11
12
|
def create_component_file
|
12
13
|
template "component.rb", File.join("app/components", class_path, "#{file_name}_component.rb")
|
@@ -14,6 +15,8 @@ module Rails
|
|
14
15
|
|
15
16
|
hook_for :test_framework
|
16
17
|
|
18
|
+
hook_for :preview, type: :boolean
|
19
|
+
|
17
20
|
hook_for :template_engine do |instance, template_engine|
|
18
21
|
instance.invoke template_engine, [instance.name]
|
19
22
|
end
|
@@ -37,6 +40,10 @@ module Rails
|
|
37
40
|
def initialize_body
|
38
41
|
attributes.map { |attr| "@#{attr.name} = #{attr.name}" }.join("\n ")
|
39
42
|
end
|
43
|
+
|
44
|
+
def initialize_call_method_for_inline?
|
45
|
+
options["inline"]
|
46
|
+
end
|
40
47
|
end
|
41
48
|
end
|
42
49
|
end
|
@@ -7,6 +7,7 @@ module Erb
|
|
7
7
|
class ComponentGenerator < Base
|
8
8
|
source_root File.expand_path("templates", __dir__)
|
9
9
|
class_option :sidecar, type: :boolean, default: false
|
10
|
+
class_option :inline, type: :boolean, default: false
|
10
11
|
|
11
12
|
def copy_view_file
|
12
13
|
template "component.html.erb", destination
|
@@ -15,10 +16,12 @@ module Erb
|
|
15
16
|
private
|
16
17
|
|
17
18
|
def destination
|
18
|
-
if options["
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
if !options["inline"]
|
20
|
+
if options["sidecar"]
|
21
|
+
File.join("app/components", class_path, "#{file_name}_component", "#{file_name}_component.html.erb")
|
22
|
+
else
|
23
|
+
File.join("app/components", class_path, "#{file_name}_component.html.erb")
|
24
|
+
end
|
22
25
|
end
|
23
26
|
end
|
24
27
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Preview
|
4
|
+
module Generators
|
5
|
+
class ComponentGenerator < ::Rails::Generators::NamedBase
|
6
|
+
source_root File.expand_path("templates", __dir__)
|
7
|
+
|
8
|
+
check_class_collision suffix: "ComponentPreview"
|
9
|
+
|
10
|
+
def create_preview_file
|
11
|
+
template "component_preview.rb", File.join("test/components/previews", class_path, "#{file_name}_component_preview.rb")
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def file_name
|
17
|
+
@_file_name ||= super.sub(/_component\z/i, "")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/view_component/base.rb
CHANGED
@@ -15,12 +15,22 @@ module ViewComponent
|
|
15
15
|
|
16
16
|
ViewContextCalledBeforeRenderError = Class.new(StandardError)
|
17
17
|
|
18
|
+
RESERVED_PARAMETER = :content
|
19
|
+
|
18
20
|
# For CSRF authenticity tokens in forms
|
19
21
|
delegate :form_authenticity_token, :protect_against_forgery?, :config, to: :helpers
|
20
22
|
|
21
23
|
class_attribute :content_areas
|
22
24
|
self.content_areas = [] # class_attribute:default doesn't work until Rails 5.2
|
23
25
|
|
26
|
+
# EXPERIMENTAL: This API is experimental and may be removed at any time.
|
27
|
+
# Hook for allowing components to do work as part of the compilation process.
|
28
|
+
#
|
29
|
+
# For example, one might compile component-specific assets at this point.
|
30
|
+
def self._after_compile
|
31
|
+
# noop
|
32
|
+
end
|
33
|
+
|
24
34
|
# Entrypoint for rendering components.
|
25
35
|
#
|
26
36
|
# view_context: ActionView context from calling view
|
@@ -264,7 +274,7 @@ module ViewComponent
|
|
264
274
|
parameter = validate_default ? collection_parameter : provided_collection_parameter
|
265
275
|
|
266
276
|
return unless parameter
|
267
|
-
return if
|
277
|
+
return if initialize_parameter_names.include?(parameter)
|
268
278
|
|
269
279
|
# If Ruby cannot parse the component class, then the initalize
|
270
280
|
# parameters will be empty and ViewComponent will not be able to render
|
@@ -281,8 +291,25 @@ module ViewComponent
|
|
281
291
|
)
|
282
292
|
end
|
283
293
|
|
294
|
+
# Ensure the component initializer does not define
|
295
|
+
# invalid parameters that could override the framework's
|
296
|
+
# methods.
|
297
|
+
def validate_initialization_parameters!
|
298
|
+
return unless initialize_parameter_names.include?(RESERVED_PARAMETER)
|
299
|
+
|
300
|
+
raise ArgumentError.new(
|
301
|
+
"#{self} initializer cannot contain " \
|
302
|
+
"`#{RESERVED_PARAMETER}` since it will override a " \
|
303
|
+
"public ViewComponent method."
|
304
|
+
)
|
305
|
+
end
|
306
|
+
|
284
307
|
private
|
285
308
|
|
309
|
+
def initialize_parameter_names
|
310
|
+
initialize_parameters.map(&:last)
|
311
|
+
end
|
312
|
+
|
286
313
|
def initialize_parameters
|
287
314
|
instance_method(:initialize).parameters
|
288
315
|
end
|
@@ -4,14 +4,17 @@ require "action_view/renderer/collection_renderer" if Rails.version.to_f >= 6.1
|
|
4
4
|
|
5
5
|
module ViewComponent
|
6
6
|
class Collection
|
7
|
+
attr_reader :component
|
8
|
+
delegate :format, to: :component
|
9
|
+
|
7
10
|
def render_in(view_context, &block)
|
8
11
|
iterator = ActionView::PartialIteration.new(@collection.size)
|
9
12
|
|
10
|
-
|
11
|
-
|
13
|
+
component.compile(raise_errors: true)
|
14
|
+
component.validate_collection_parameter!(validate_default: true)
|
12
15
|
|
13
16
|
@collection.map do |item|
|
14
|
-
content =
|
17
|
+
content = component.new(**component_options(item, iterator)).render_in(view_context, &block)
|
15
18
|
iterator.iterate!
|
16
19
|
content
|
17
20
|
end.join.html_safe
|
@@ -34,8 +37,8 @@ module ViewComponent
|
|
34
37
|
end
|
35
38
|
|
36
39
|
def component_options(item, iterator)
|
37
|
-
item_options = {
|
38
|
-
item_options[
|
40
|
+
item_options = { component.collection_parameter => item }
|
41
|
+
item_options[component.collection_counter_parameter] = iterator.index + 1 if component.counter_argument_present?
|
39
42
|
|
40
43
|
@options.merge(item_options)
|
41
44
|
end
|
@@ -46,7 +46,10 @@ module ViewComponent
|
|
46
46
|
instance_method(:initialize).parameters.map(&:second).include?(collection_counter_parameter)
|
47
47
|
end
|
48
48
|
|
49
|
-
|
49
|
+
if raise_errors
|
50
|
+
component_class.validate_initialization_parameters!
|
51
|
+
component_class.validate_collection_parameter!
|
52
|
+
end
|
50
53
|
|
51
54
|
templates.each do |template|
|
52
55
|
# Remove existing compiled template methods,
|
@@ -64,6 +67,8 @@ module ViewComponent
|
|
64
67
|
|
65
68
|
define_render_template_for
|
66
69
|
|
70
|
+
component_class._after_compile
|
71
|
+
|
67
72
|
CompileCache.register(component_class)
|
68
73
|
end
|
69
74
|
|
@@ -163,9 +168,8 @@ module ViewComponent
|
|
163
168
|
# end
|
164
169
|
#
|
165
170
|
# Without this, `MyOtherComponent` will not look for `my_component/my_other_component.html.erb`
|
166
|
-
nested_component_files = if component_class.name.include?("::")
|
167
|
-
|
168
|
-
Dir["#{directory}/#{nested_component_path}/#{component_name}.*{#{extensions}}"]
|
171
|
+
nested_component_files = if component_class.name.include?("::") && component_name != filename
|
172
|
+
Dir["#{directory}/#{filename}/#{component_name}.*{#{extensions}}"]
|
169
173
|
else
|
170
174
|
[]
|
171
175
|
end
|
@@ -205,7 +209,6 @@ module ViewComponent
|
|
205
209
|
end
|
206
210
|
end
|
207
211
|
|
208
|
-
# :nocov:
|
209
212
|
def compiled_template(file_path)
|
210
213
|
handler = ActionView::Template.handler_for_extension(File.extname(file_path).gsub(".", ""))
|
211
214
|
template = File.read(file_path)
|
@@ -216,7 +219,6 @@ module ViewComponent
|
|
216
219
|
handler.call(OpenStruct.new(source: template, identifier: component_class.identifier, type: component_class.type))
|
217
220
|
end
|
218
221
|
end
|
219
|
-
# :nocov:
|
220
222
|
|
221
223
|
def call_method_name(variant)
|
222
224
|
if variant.present? && variants.include?(variant)
|
@@ -22,17 +22,21 @@ module ViewComponent
|
|
22
22
|
# If there is no slot renderable, we evaluate the block passed to
|
23
23
|
# the slot and return it.
|
24
24
|
def to_s
|
25
|
-
if defined?(@
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
@_content
|
33
|
-
|
34
|
-
@_content_block
|
25
|
+
return @content if defined?(@content)
|
26
|
+
|
27
|
+
view_context = @parent.send(:view_context)
|
28
|
+
@content = view_context.capture do
|
29
|
+
if defined?(@_component_instance)
|
30
|
+
# render_in is faster than `parent.render`
|
31
|
+
@_component_instance.render_in(view_context, &@_content_block)
|
32
|
+
elsif defined?(@_content)
|
33
|
+
@_content
|
34
|
+
elsif defined?(@_content_block)
|
35
|
+
@_content_block.call
|
36
|
+
end
|
35
37
|
end
|
38
|
+
|
39
|
+
@content
|
36
40
|
end
|
37
41
|
|
38
42
|
# Allow access to public component methods via the wrapper
|
@@ -58,8 +62,12 @@ module ViewComponent
|
|
58
62
|
@_component_instance.public_send(symbol, *args, &block)
|
59
63
|
end
|
60
64
|
|
65
|
+
def html_safe?
|
66
|
+
to_s.html_safe?
|
67
|
+
end
|
68
|
+
|
61
69
|
def respond_to_missing?(symbol, include_all = false)
|
62
|
-
@_component_instance.respond_to?(symbol, include_all)
|
70
|
+
defined?(@_component_instance) && @_component_instance.respond_to?(symbol, include_all)
|
63
71
|
end
|
64
72
|
end
|
65
73
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: view_component
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.25.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GitHub Open Source
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -198,7 +198,7 @@ dependencies:
|
|
198
198
|
- - "~>"
|
199
199
|
- !ruby/object:Gem::Version
|
200
200
|
version: '0.13'
|
201
|
-
description:
|
201
|
+
description:
|
202
202
|
email:
|
203
203
|
- opensource+view_component@github.com
|
204
204
|
executables: []
|
@@ -219,6 +219,8 @@ files:
|
|
219
219
|
- lib/rails/generators/erb/templates/component.html.erb.tt
|
220
220
|
- lib/rails/generators/haml/component_generator.rb
|
221
221
|
- lib/rails/generators/haml/templates/component.html.haml.tt
|
222
|
+
- lib/rails/generators/preview/component_generator.rb
|
223
|
+
- lib/rails/generators/preview/templates/component_preview.rb.tt
|
222
224
|
- lib/rails/generators/rspec/component_generator.rb
|
223
225
|
- lib/rails/generators/rspec/templates/component_spec.rb.tt
|
224
226
|
- lib/rails/generators/slim/component_generator.rb
|
@@ -253,7 +255,7 @@ licenses:
|
|
253
255
|
- MIT
|
254
256
|
metadata:
|
255
257
|
allowed_push_host: https://rubygems.org
|
256
|
-
post_install_message:
|
258
|
+
post_install_message:
|
257
259
|
rdoc_options: []
|
258
260
|
require_paths:
|
259
261
|
- lib
|
@@ -268,8 +270,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
268
270
|
- !ruby/object:Gem::Version
|
269
271
|
version: '0'
|
270
272
|
requirements: []
|
271
|
-
rubygems_version: 3.
|
272
|
-
signing_key:
|
273
|
+
rubygems_version: 3.0.3
|
274
|
+
signing_key:
|
273
275
|
specification_version: 4
|
274
276
|
summary: View components for Rails
|
275
277
|
test_files: []
|