view_component 2.23.2 → 2.26.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 +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 +68 -5
- data/lib/view_component/collection.rb +0 -1
- data/lib/view_component/compiler.rb +7 -27
- data/lib/view_component/slot_v2.rb +14 -2
- 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 +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 071c4caebc8e0dd567d8850adff146e65f6c8c1fe600b866f072d9bfa94bbc46
|
4
|
+
data.tar.gz: 64df3c2eb8d27431da23a2c628de6c9c00d7988130494d37319f4a01d653fd9c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 69bc43697d70dfb9b96280f47b80c06d1020fd180c01cbc6ae8c8416c3e1b97ffc6587d00741fa81743ae482a316e653790db5af2584c16baf3839a58b809195
|
7
|
+
data.tar.gz: 636d5d91edb07cb90f44e3fc21e7ee63c3c115d1f5fbf7666619205b628761028c4963c65b30a181f27fbbd0bf9539cab0ec3271a48b4d747d7a705528218f11
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,60 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
-
##
|
3
|
+
## main
|
4
|
+
|
5
|
+
## 2.26.1
|
6
|
+
|
7
|
+
* Fix bug that raises when trying to use a collection before the component has been compiled.
|
8
|
+
|
9
|
+
*Blake Williams*
|
10
|
+
|
11
|
+
## 2.26.0
|
12
|
+
|
13
|
+
* Lazily evaluate component `content` in `render?`, preventing the `content` block from being evaluated when `render?` returns false.
|
14
|
+
|
15
|
+
*Blake Williams*
|
16
|
+
|
17
|
+
* Do not generate template when using `--inline` flag.
|
18
|
+
|
19
|
+
*Hans Lemuet*
|
20
|
+
|
21
|
+
* Add `--inline` option to the Haml and Slim generators
|
22
|
+
|
23
|
+
*Hans Lemuet*
|
24
|
+
|
25
|
+
## 2.25.1
|
26
|
+
|
27
|
+
* Experimental: call `._after_compile` class method after a component is compiled.
|
28
|
+
|
29
|
+
*Joel Hawksley*
|
30
|
+
|
31
|
+
* Fix bug where SlotV2 was rendered as an HTML string when using Slim.
|
32
|
+
|
33
|
+
*Manuel Puyol*
|
34
|
+
|
35
|
+
## 2.25.0
|
36
|
+
|
37
|
+
* Add `--preview` generator option to create an associated preview file.
|
38
|
+
|
39
|
+
*Bob Maerten*
|
40
|
+
|
41
|
+
* Add argument validation to avoid `content` override.
|
42
|
+
|
43
|
+
*Manuel Puyol*
|
44
|
+
|
45
|
+
## 2.24.0
|
46
|
+
|
47
|
+
* Add `--inline` option to the erb generator. Prevents default erb template from being created and creates a component with a call method.
|
48
|
+
|
49
|
+
*Nachiket Pusalkar*
|
50
|
+
|
51
|
+
* Add test case for checking presence of `content` in `#render?`.
|
52
|
+
|
53
|
+
*Joel Hawksley*
|
54
|
+
|
55
|
+
* Rename `master` branch to `main`.
|
56
|
+
|
57
|
+
*Joel Hawksley*
|
4
58
|
|
5
59
|
## 2.23.2
|
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,41 @@ 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
|
+
|
327
|
+
def collection_parameter
|
328
|
+
if provided_collection_parameter
|
329
|
+
provided_collection_parameter
|
330
|
+
else
|
331
|
+
name && name.demodulize.underscore.chomp("_component").to_sym
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
def collection_counter_parameter
|
336
|
+
"#{collection_parameter}_counter".to_sym
|
337
|
+
end
|
338
|
+
|
339
|
+
def counter_argument_present?
|
340
|
+
instance_method(:initialize).parameters.map(&:second).include?(collection_counter_parameter)
|
341
|
+
end
|
342
|
+
|
284
343
|
private
|
285
344
|
|
345
|
+
def initialize_parameter_names
|
346
|
+
initialize_parameters.map(&:last)
|
347
|
+
end
|
348
|
+
|
286
349
|
def initialize_parameters
|
287
350
|
instance_method(:initialize).parameters
|
288
351
|
end
|
@@ -10,7 +10,6 @@ module ViewComponent
|
|
10
10
|
def render_in(view_context, &block)
|
11
11
|
iterator = ActionView::PartialIteration.new(@collection.size)
|
12
12
|
|
13
|
-
component.compile(raise_errors: true)
|
14
13
|
component.validate_collection_parameter!(validate_default: true)
|
15
14
|
|
16
15
|
@collection.map do |item|
|
@@ -24,30 +24,11 @@ module ViewComponent
|
|
24
24
|
)
|
25
25
|
end
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
component_class.remove_possible_singleton_method(:collection_counter_parameter)
|
31
|
-
component_class.remove_possible_singleton_method(:counter_argument_present?)
|
32
|
-
|
33
|
-
component_class.define_singleton_method(:collection_parameter) do
|
34
|
-
if provided_collection_parameter
|
35
|
-
provided_collection_parameter
|
36
|
-
else
|
37
|
-
name.demodulize.underscore.chomp("_component").to_sym
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
component_class.define_singleton_method(:collection_counter_parameter) do
|
42
|
-
"#{collection_parameter}_counter".to_sym
|
27
|
+
if raise_errors
|
28
|
+
component_class.validate_initialization_parameters!
|
29
|
+
component_class.validate_collection_parameter!
|
43
30
|
end
|
44
31
|
|
45
|
-
component_class.define_singleton_method(:counter_argument_present?) do
|
46
|
-
instance_method(:initialize).parameters.map(&:second).include?(collection_counter_parameter)
|
47
|
-
end
|
48
|
-
|
49
|
-
component_class.validate_collection_parameter! if raise_errors
|
50
|
-
|
51
32
|
templates.each do |template|
|
52
33
|
# Remove existing compiled template methods,
|
53
34
|
# as Ruby warns when redefining a method.
|
@@ -64,6 +45,8 @@ module ViewComponent
|
|
64
45
|
|
65
46
|
define_render_template_for
|
66
47
|
|
48
|
+
component_class._after_compile
|
49
|
+
|
67
50
|
CompileCache.register(component_class)
|
68
51
|
end
|
69
52
|
|
@@ -163,9 +146,8 @@ module ViewComponent
|
|
163
146
|
# end
|
164
147
|
#
|
165
148
|
# 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}}"]
|
149
|
+
nested_component_files = if component_class.name.include?("::") && component_name != filename
|
150
|
+
Dir["#{directory}/#{filename}/#{component_name}.*{#{extensions}}"]
|
169
151
|
else
|
170
152
|
[]
|
171
153
|
end
|
@@ -205,7 +187,6 @@ module ViewComponent
|
|
205
187
|
end
|
206
188
|
end
|
207
189
|
|
208
|
-
# :nocov:
|
209
190
|
def compiled_template(file_path)
|
210
191
|
handler = ActionView::Template.handler_for_extension(File.extname(file_path).gsub(".", ""))
|
211
192
|
template = File.read(file_path)
|
@@ -216,7 +197,6 @@ module ViewComponent
|
|
216
197
|
handler.call(OpenStruct.new(source: template, identifier: component_class.identifier, type: component_class.type))
|
217
198
|
end
|
218
199
|
end
|
219
|
-
# :nocov:
|
220
200
|
|
221
201
|
def call_method_name(variant)
|
222
202
|
if variant.present? && variants.include?(variant)
|
@@ -22,17 +22,25 @@ 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
|
+
if defined?(@_content_block)
|
32
|
+
@_component_instance.render_in(view_context, &@_content_block)
|
33
|
+
else
|
34
|
+
@_component_instance.render_in(view_context)
|
35
|
+
end
|
30
36
|
elsif defined?(@_content)
|
31
37
|
@_content
|
32
38
|
elsif defined?(@_content_block)
|
33
39
|
@_content_block.call
|
34
40
|
end
|
35
41
|
end
|
42
|
+
|
43
|
+
@content
|
36
44
|
end
|
37
45
|
|
38
46
|
# Allow access to public component methods via the wrapper
|
@@ -58,6 +66,10 @@ module ViewComponent
|
|
58
66
|
@_component_instance.public_send(symbol, *args, &block)
|
59
67
|
end
|
60
68
|
|
69
|
+
def html_safe?
|
70
|
+
to_s.html_safe?
|
71
|
+
end
|
72
|
+
|
61
73
|
def respond_to_missing?(symbol, include_all = false)
|
62
74
|
defined?(@_component_instance) && @_component_instance.respond_to?(symbol, include_all)
|
63
75
|
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.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GitHub Open Source
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -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
|
@@ -268,7 +270,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
268
270
|
- !ruby/object:Gem::Version
|
269
271
|
version: '0'
|
270
272
|
requirements: []
|
271
|
-
rubygems_version: 3.
|
273
|
+
rubygems_version: 3.0.3
|
272
274
|
signing_key:
|
273
275
|
specification_version: 4
|
274
276
|
summary: View components for Rails
|