view_component 2.23.1 → 2.26.0
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.
- 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: []
|