view_component 2.23.0 → 2.25.1
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.
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: []
|