view_component 2.23.1 → 2.26.0
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 +55 -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 +4 -1
- data/lib/rails/generators/haml/component_generator.rb +3 -1
- data/lib/rails/generators/preview/component_generator.rb +21 -0
- data/lib/rails/generators/preview/templates/component_preview.rb.tt +5 -0
- data/lib/rails/generators/slim/component_generator.rb +3 -1
- data/lib/view_component/base.rb +52 -5
- data/lib/view_component/collection.rb +7 -5
- data/lib/view_component/compiler.rb +8 -6
- data/lib/view_component/slot_v2.rb +9 -1
- data/lib/view_component/slotable.rb +7 -1
- data/lib/view_component/slotable_v2.rb +2 -0
- 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: 5a1fb023bfaa4a1ea26166ddd22b5fcd4a7e5f5da1bc7f10039c2bc557f1a94c
|
4
|
+
data.tar.gz: 5274b49f0e18f521b15181c70aeb4edcf3458cba13dc8c8ea59b9331d26681c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fc60826197c5dbd54ebd53517ff59eab097449913802a4e17df9db33ab54d1daf8ff2e00d1629058962c267274ec7fe6e362aa036206d379e27c7c832db7d05c
|
7
|
+
data.tar.gz: b3a65f7a829d9e9fc675904d61c6d1c1015c194c5a7abe596961b3cb20a3a4c2045f1ce49b1b98a551c4b745688c38610d3a86040c1f7f0229c3b247a51f9c65
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,60 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
-
##
|
3
|
+
## main
|
4
|
+
|
5
|
+
## 2.26.0
|
6
|
+
|
7
|
+
* Lazily evaluate component `content` in `render?`, preventing the `content` block from being evaluated when `render?` returns false.
|
8
|
+
|
9
|
+
*Blake Williams*
|
10
|
+
|
11
|
+
* Do not generate template when using `--inline` flag.
|
12
|
+
|
13
|
+
*Hans Lemuet*
|
14
|
+
|
15
|
+
* Add `--inline` option to the Haml and Slim generators
|
16
|
+
|
17
|
+
*Hans Lemuet*
|
18
|
+
|
19
|
+
## 2.25.1
|
20
|
+
|
21
|
+
* Experimental: call `._after_compile` class method after a component is compiled.
|
22
|
+
|
23
|
+
*Joel Hawksley*
|
24
|
+
|
25
|
+
* Fix bug where SlotV2 was rendered as an HTML string when using Slim.
|
26
|
+
|
27
|
+
*Manuel Puyol*
|
28
|
+
|
29
|
+
## 2.25.0
|
30
|
+
|
31
|
+
* Add `--preview` generator option to create an associated preview file.
|
32
|
+
|
33
|
+
*Bob Maerten*
|
34
|
+
|
35
|
+
* Add argument validation to avoid `content` override.
|
36
|
+
|
37
|
+
*Manuel Puyol*
|
38
|
+
|
39
|
+
## 2.24.0
|
40
|
+
|
41
|
+
* Add `--inline` option to the erb generator. Prevents default erb template from being created and creates a component with a call method.
|
42
|
+
|
43
|
+
*Nachiket Pusalkar*
|
44
|
+
|
45
|
+
* Add test case for checking presence of `content` in `#render?`.
|
46
|
+
|
47
|
+
*Joel Hawksley*
|
48
|
+
|
49
|
+
* Rename `master` branch to `main`.
|
50
|
+
|
51
|
+
*Joel Hawksley*
|
52
|
+
|
53
|
+
## 2.23.2
|
54
|
+
|
55
|
+
* Fix bug where rendering a component `with_collection` from a controller raised an error.
|
56
|
+
|
57
|
+
*Joel Hawksley*
|
4
58
|
|
5
59
|
## 2.23.1
|
6
60
|
|
@@ -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,9 +7,12 @@ 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
|
+
unless options["inline"]
|
14
|
+
template "component.html.erb", destination
|
15
|
+
end
|
13
16
|
end
|
14
17
|
|
15
18
|
private
|
@@ -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
|
@@ -68,8 +78,8 @@ module ViewComponent
|
|
68
78
|
old_current_template = @current_template
|
69
79
|
@current_template = self
|
70
80
|
|
71
|
-
|
72
|
-
@
|
81
|
+
@_content_evaluated = false
|
82
|
+
@_render_in_block = block
|
73
83
|
|
74
84
|
before_render
|
75
85
|
|
@@ -167,7 +177,20 @@ module ViewComponent
|
|
167
177
|
@request ||= controller.request
|
168
178
|
end
|
169
179
|
|
170
|
-
attr_reader :
|
180
|
+
attr_reader :view_context
|
181
|
+
|
182
|
+
def content
|
183
|
+
return @_content if defined?(@_content)
|
184
|
+
@_content_evaluated = true
|
185
|
+
|
186
|
+
@_content = if @view_context && @_render_in_block
|
187
|
+
view_context.capture(self, &@_render_in_block)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def content_evaluated?
|
192
|
+
@_content_evaluated
|
193
|
+
end
|
171
194
|
|
172
195
|
# The controller used for testing components.
|
173
196
|
# Defaults to ApplicationController. This should be set early
|
@@ -246,7 +269,14 @@ module ViewComponent
|
|
246
269
|
if areas.include?(:content)
|
247
270
|
raise ArgumentError.new ":content is a reserved content area name. Please use another name, such as ':body'"
|
248
271
|
end
|
249
|
-
|
272
|
+
|
273
|
+
areas.each do |area|
|
274
|
+
define_method area.to_sym do
|
275
|
+
content unless content_evaluated? # ensure content is loaded so content_areas will be defined
|
276
|
+
instance_variable_get(:"@#{area}") if instance_variable_defined?(:"@#{area}")
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
250
280
|
self.content_areas = areas
|
251
281
|
end
|
252
282
|
|
@@ -264,7 +294,7 @@ module ViewComponent
|
|
264
294
|
parameter = validate_default ? collection_parameter : provided_collection_parameter
|
265
295
|
|
266
296
|
return unless parameter
|
267
|
-
return if
|
297
|
+
return if initialize_parameter_names.include?(parameter)
|
268
298
|
|
269
299
|
# If Ruby cannot parse the component class, then the initalize
|
270
300
|
# parameters will be empty and ViewComponent will not be able to render
|
@@ -281,8 +311,25 @@ module ViewComponent
|
|
281
311
|
)
|
282
312
|
end
|
283
313
|
|
314
|
+
# Ensure the component initializer does not define
|
315
|
+
# invalid parameters that could override the framework's
|
316
|
+
# methods.
|
317
|
+
def validate_initialization_parameters!
|
318
|
+
return unless initialize_parameter_names.include?(RESERVED_PARAMETER)
|
319
|
+
|
320
|
+
raise ArgumentError.new(
|
321
|
+
"#{self} initializer cannot contain " \
|
322
|
+
"`#{RESERVED_PARAMETER}` since it will override a " \
|
323
|
+
"public ViewComponent method."
|
324
|
+
)
|
325
|
+
end
|
326
|
+
|
284
327
|
private
|
285
328
|
|
329
|
+
def initialize_parameter_names
|
330
|
+
initialize_parameters.map(&:last)
|
331
|
+
end
|
332
|
+
|
286
333
|
def initialize_parameters
|
287
334
|
instance_method(:initialize).parameters
|
288
335
|
end
|
@@ -4,14 +4,16 @@ 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
|
-
@component.validate_collection_parameter!(validate_default: true)
|
13
|
+
component.validate_collection_parameter!(validate_default: true)
|
12
14
|
|
13
15
|
@collection.map do |item|
|
14
|
-
content =
|
16
|
+
content = component.new(**component_options(item, iterator)).render_in(view_context, &block)
|
15
17
|
iterator.iterate!
|
16
18
|
content
|
17
19
|
end.join.html_safe
|
@@ -34,8 +36,8 @@ module ViewComponent
|
|
34
36
|
end
|
35
37
|
|
36
38
|
def component_options(item, iterator)
|
37
|
-
item_options = {
|
38
|
-
item_options[
|
39
|
+
item_options = { component.collection_parameter => item }
|
40
|
+
item_options[component.collection_counter_parameter] = iterator.index + 1 if component.counter_argument_present?
|
39
41
|
|
40
42
|
@options.merge(item_options)
|
41
43
|
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,8 +22,10 @@ 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
|
+
return @content if defined?(@content)
|
26
|
+
|
25
27
|
view_context = @parent.send(:view_context)
|
26
|
-
view_context.capture do
|
28
|
+
@content = view_context.capture do
|
27
29
|
if defined?(@_component_instance)
|
28
30
|
# render_in is faster than `parent.render`
|
29
31
|
@_component_instance.render_in(view_context, &@_content_block)
|
@@ -33,6 +35,8 @@ module ViewComponent
|
|
33
35
|
@_content_block.call
|
34
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,6 +62,10 @@ 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
70
|
defined?(@_component_instance) && @_component_instance.respond_to?(symbol, include_all)
|
63
71
|
end
|
@@ -51,11 +51,17 @@ module ViewComponent
|
|
51
51
|
if collection
|
52
52
|
class_eval <<-RUBY
|
53
53
|
def #{accessor_name}
|
54
|
+
content unless content_evaluated? # ensure content is loaded so slots will be defined
|
54
55
|
#{instance_variable_name} ||= []
|
55
56
|
end
|
56
57
|
RUBY
|
57
58
|
else
|
58
|
-
|
59
|
+
class_eval <<-RUBY
|
60
|
+
def #{accessor_name}
|
61
|
+
content unless content_evaluated? # ensure content is loaded so slots will be defined
|
62
|
+
#{instance_variable_name} if defined?(#{instance_variable_name})
|
63
|
+
end
|
64
|
+
RUBY
|
59
65
|
end
|
60
66
|
|
61
67
|
# Default class_name to ViewComponent::Slot
|
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.26.0
|
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-22 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: []
|