view_component 3.20.0 → 3.21.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/docs/CHANGELOG.md +30 -0
- data/lib/rails/generators/component/component_generator.rb +2 -1
- data/lib/rails/generators/component/templates/component.rb.tt +1 -1
- data/lib/view_component/base.rb +18 -30
- data/lib/view_component/compiler.rb +4 -13
- data/lib/view_component/instrumentation.rb +1 -1
- data/lib/view_component/template.rb +8 -0
- data/lib/view_component/version.rb +1 -1
- metadata +16 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 24be9824d2f5208831e8de57930415019c781a1245224659efb9258372dcafbc
|
4
|
+
data.tar.gz: 33182c814b14959c85370e274619a3da70ea19906dd40c8d0be0cd12c9f16a2b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d856adb4c86acc808277c7fcc17291b41328b932b53991db003dccab6e23f2a02177e200065e78d3004f8233df98b0926202138b8b536f67c8f848f876231e2
|
7
|
+
data.tar.gz: a7c6b583fd6eaf4bdb20cdc9d7ca86ed0a5e818e90d1099c5fd799d2127122c058d5d58285251ea0713aeb73d719cabad8ab971e994e0f658767235089953dfd
|
data/docs/CHANGELOG.md
CHANGED
@@ -10,6 +10,36 @@ nav_order: 5
|
|
10
10
|
|
11
11
|
## main
|
12
12
|
|
13
|
+
## 3.21.0
|
14
|
+
|
15
|
+
* Updates testing docs to include an example of how to use with RSpec.
|
16
|
+
|
17
|
+
*Rylan Bowers*
|
18
|
+
|
19
|
+
* Add `--skip-suffix` option to component generator.
|
20
|
+
|
21
|
+
*KAWAKAMI Moeki*
|
22
|
+
|
23
|
+
* Add FreeATS to list of companies using ViewComponent.
|
24
|
+
|
25
|
+
*Ilia Liamshin*
|
26
|
+
|
27
|
+
* Ensure HTML output safety wrapper is used for all inline templates.
|
28
|
+
|
29
|
+
*Joel Hawksley*
|
30
|
+
|
31
|
+
* Expose `.identifier` method as part of public API.
|
32
|
+
|
33
|
+
*Joel Hawksley*
|
34
|
+
|
35
|
+
* Add rails 8 support to CI.
|
36
|
+
|
37
|
+
*Reegan Viljoen*
|
38
|
+
|
39
|
+
* Updates ActionText compatibility documentation to reference `rich_textarea_tag` for Rails 8.0 support.
|
40
|
+
|
41
|
+
*Alvin Crespo*
|
42
|
+
|
13
43
|
## 3.20.0
|
14
44
|
|
15
45
|
* Allow rendering `with_collection` to accept an optional `spacer_component` to be rendered between each item.
|
@@ -19,9 +19,10 @@ module Rails
|
|
19
19
|
class_option :sidecar, type: :boolean, default: false
|
20
20
|
class_option :stimulus, type: :boolean,
|
21
21
|
default: ViewComponent::Base.config.generate.stimulus_controller
|
22
|
+
class_option :skip_suffix, type: :boolean, default: false
|
22
23
|
|
23
24
|
def create_component_file
|
24
|
-
template "component.rb", File.join(component_path, class_path, "#{file_name}_component.rb")
|
25
|
+
template "component.rb", File.join(component_path, class_path, "#{file_name}#{options[:skip_suffix] ? "" : "_component"}.rb")
|
25
26
|
end
|
26
27
|
|
27
28
|
hook_for :test_framework
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
<% module_namespacing do -%>
|
4
|
-
class <%= class_name
|
4
|
+
class <%= class_name %><%= options[:skip_suffix] ? "" : "Component" %> < <%= parent_class %>
|
5
5
|
<%- if initialize_signature -%>
|
6
6
|
def initialize(<%= initialize_signature %>)
|
7
7
|
<%= initialize_body %>
|
data/lib/view_component/base.rb
CHANGED
@@ -108,14 +108,7 @@ module ViewComponent
|
|
108
108
|
before_render
|
109
109
|
|
110
110
|
if render?
|
111
|
-
rendered_template =
|
112
|
-
if compiler.renders_template_for?(@__vc_variant, __vc_request&.format&.to_sym)
|
113
|
-
render_template_for(@__vc_variant, __vc_request&.format&.to_sym)
|
114
|
-
else
|
115
|
-
maybe_escape_html(render_template_for(@__vc_variant, __vc_request&.format&.to_sym)) do
|
116
|
-
Kernel.warn("WARNING: The #{self.class} component rendered HTML-unsafe output. The output will be automatically escaped, but you may want to investigate.")
|
117
|
-
end
|
118
|
-
end.to_s
|
111
|
+
rendered_template = render_template_for(@__vc_variant, __vc_request&.format&.to_sym).to_s
|
119
112
|
|
120
113
|
# Avoid allocating new string when output_preamble and output_postamble are blank
|
121
114
|
if output_preamble.blank? && output_postamble.blank?
|
@@ -358,10 +351,6 @@ module ViewComponent
|
|
358
351
|
end
|
359
352
|
end
|
360
353
|
|
361
|
-
def compiler
|
362
|
-
@compiler ||= self.class.compiler
|
363
|
-
end
|
364
|
-
|
365
354
|
# Set the controller used for testing components:
|
366
355
|
#
|
367
356
|
# ```ruby
|
@@ -457,8 +446,16 @@ module ViewComponent
|
|
457
446
|
# Defaults to `false`.
|
458
447
|
|
459
448
|
class << self
|
449
|
+
# The file path of the component Ruby file.
|
450
|
+
#
|
451
|
+
# @return [String]
|
452
|
+
attr_reader :identifier
|
453
|
+
|
454
|
+
# @private
|
455
|
+
attr_writer :identifier
|
456
|
+
|
460
457
|
# @private
|
461
|
-
attr_accessor :
|
458
|
+
attr_accessor :virtual_path
|
462
459
|
|
463
460
|
# Find sidecar files for the given extensions.
|
464
461
|
#
|
@@ -468,13 +465,13 @@ module ViewComponent
|
|
468
465
|
# For example, one might collect sidecar CSS files that need to be compiled.
|
469
466
|
# @param extensions [Array<String>] Extensions of which to return matching sidecar files.
|
470
467
|
def sidecar_files(extensions)
|
471
|
-
return [] unless
|
468
|
+
return [] unless identifier
|
472
469
|
|
473
470
|
extensions = extensions.join(",")
|
474
471
|
|
475
472
|
# view files in a directory named like the component
|
476
|
-
directory = File.dirname(
|
477
|
-
filename = File.basename(
|
473
|
+
directory = File.dirname(identifier)
|
474
|
+
filename = File.basename(identifier, ".rb")
|
478
475
|
component_name = name.demodulize.underscore
|
479
476
|
|
480
477
|
# Add support for nested components defined in the same file.
|
@@ -499,7 +496,7 @@ module ViewComponent
|
|
499
496
|
|
500
497
|
sidecar_directory_files = Dir["#{directory}/#{component_name}/#{filename}.*{#{extensions}}"]
|
501
498
|
|
502
|
-
(sidecar_files - [
|
499
|
+
(sidecar_files - [identifier] + sidecar_directory_files + nested_component_files).uniq
|
503
500
|
end
|
504
501
|
|
505
502
|
# Render a component for each element in a collection ([documentation](/guide/collections)):
|
@@ -548,11 +545,11 @@ module ViewComponent
|
|
548
545
|
# has been re-defined by the consuming application, likely in ApplicationComponent.
|
549
546
|
# We use `base_label` method here instead of `label` to avoid cases where the method
|
550
547
|
# owner is included in a prefix like `ApplicationComponent.inherited`.
|
551
|
-
child.
|
548
|
+
child.identifier = caller_locations(1, 10).reject { |l| l.base_label == "inherited" }[0].path
|
552
549
|
|
553
550
|
# If Rails application is loaded, removes the first part of the path and the extension.
|
554
551
|
if defined?(Rails) && Rails.application
|
555
|
-
child.virtual_path = child.
|
552
|
+
child.virtual_path = child.identifier.gsub(
|
556
553
|
/(.*#{Regexp.quote(ViewComponent::Base.config.view_component_path)})|(\.rb)/, ""
|
557
554
|
)
|
558
555
|
end
|
@@ -590,15 +587,6 @@ module ViewComponent
|
|
590
587
|
@__vc_compiler ||= Compiler.new(self)
|
591
588
|
end
|
592
589
|
|
593
|
-
# @private
|
594
|
-
def identifier
|
595
|
-
# :nocov:
|
596
|
-
Kernel.warn("WARNING: The #{self.class}.identifier is undocumented and was meant for internal framework usage only. As it is no longer used by the framework it will be removed in a coming non-breaking ViewComponent release.")
|
597
|
-
|
598
|
-
source_location
|
599
|
-
# :nocov:
|
600
|
-
end
|
601
|
-
|
602
590
|
# Set the parameter name used when rendering elements of a collection ([documentation](/guide/collections)):
|
603
591
|
#
|
604
592
|
# ```ruby
|
@@ -636,7 +624,7 @@ module ViewComponent
|
|
636
624
|
# validate that the default parameter name
|
637
625
|
# is accepted, as support for collection
|
638
626
|
# rendering is optional.
|
639
|
-
# @private
|
627
|
+
# @private
|
640
628
|
def validate_collection_parameter!(validate_default: false)
|
641
629
|
parameter = validate_default ? collection_parameter : provided_collection_parameter
|
642
630
|
|
@@ -656,7 +644,7 @@ module ViewComponent
|
|
656
644
|
# Ensure the component initializer doesn't define
|
657
645
|
# invalid parameters that could override the framework's
|
658
646
|
# methods.
|
659
|
-
# @private
|
647
|
+
# @private
|
660
648
|
def validate_initialization_parameters!
|
661
649
|
return unless initialize_parameter_names.include?(RESERVED_PARAMETER)
|
662
650
|
|
@@ -13,7 +13,6 @@ module ViewComponent
|
|
13
13
|
def initialize(component)
|
14
14
|
@component = component
|
15
15
|
@lock = Mutex.new
|
16
|
-
@rendered_templates = Set.new
|
17
16
|
end
|
18
17
|
|
19
18
|
def compiled?
|
@@ -56,10 +55,6 @@ module ViewComponent
|
|
56
55
|
end
|
57
56
|
end
|
58
57
|
|
59
|
-
def renders_template_for?(variant, format)
|
60
|
-
@rendered_templates.include?([variant, format])
|
61
|
-
end
|
62
|
-
|
63
58
|
private
|
64
59
|
|
65
60
|
attr_reader :templates
|
@@ -71,9 +66,9 @@ module ViewComponent
|
|
71
66
|
|
72
67
|
method_body =
|
73
68
|
if @templates.one?
|
74
|
-
@templates.first.
|
69
|
+
@templates.first.safe_method_name_call
|
75
70
|
elsif (template = @templates.find(&:inline?))
|
76
|
-
template.
|
71
|
+
template.safe_method_name_call
|
77
72
|
else
|
78
73
|
branches = []
|
79
74
|
|
@@ -88,13 +83,13 @@ module ViewComponent
|
|
88
83
|
].join(" && ")
|
89
84
|
end
|
90
85
|
|
91
|
-
branches << [conditional, template.
|
86
|
+
branches << [conditional, template.safe_method_name_call]
|
92
87
|
end
|
93
88
|
|
94
89
|
out = branches.each_with_object(+"") do |(conditional, branch_body), memo|
|
95
90
|
memo << "#{(!memo.present?) ? "if" : "elsif"} #{conditional}\n #{branch_body}\n"
|
96
91
|
end
|
97
|
-
out << "else\n #{templates.find { _1.variant.nil? && _1.default_format? }.
|
92
|
+
out << "else\n #{templates.find { _1.variant.nil? && _1.default_format? }.safe_method_name_call}\nend"
|
98
93
|
end
|
99
94
|
|
100
95
|
@component.silence_redefinition_of_method(:render_template_for)
|
@@ -196,10 +191,6 @@ module ViewComponent
|
|
196
191
|
variant: variant
|
197
192
|
)
|
198
193
|
|
199
|
-
# TODO: We should consider inlining the HTML output safety logic into the compiled render_template_for
|
200
|
-
# instead of this indirect approach
|
201
|
-
@rendered_templates << [out.variant, out.this_format]
|
202
|
-
|
203
194
|
out
|
204
195
|
end
|
205
196
|
|
@@ -59,6 +59,14 @@ module ViewComponent
|
|
59
59
|
@component.define_method(safe_method_name, @component.instance_method(@call_method_name))
|
60
60
|
end
|
61
61
|
|
62
|
+
def safe_method_name_call
|
63
|
+
return safe_method_name unless inline_call?
|
64
|
+
|
65
|
+
"maybe_escape_html(#{safe_method_name}) " \
|
66
|
+
"{ Kernel.warn('WARNING: The #{@component} component rendered HTML-unsafe output. " \
|
67
|
+
"The output will be automatically escaped, but you may want to investigate.') } "
|
68
|
+
end
|
69
|
+
|
62
70
|
def requires_compiled_superclass?
|
63
71
|
inline_call? && !defined_on_self?
|
64
72
|
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: 3.
|
4
|
+
version: 3.21.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ViewComponent Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-12-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -324,6 +324,20 @@ dependencies:
|
|
324
324
|
- - '='
|
325
325
|
- !ruby/object:Gem::Version
|
326
326
|
version: 4.9.0
|
327
|
+
- !ruby/object:Gem::Dependency
|
328
|
+
name: sprockets-rails
|
329
|
+
requirement: !ruby/object:Gem::Requirement
|
330
|
+
requirements:
|
331
|
+
- - "~>"
|
332
|
+
- !ruby/object:Gem::Version
|
333
|
+
version: 3.4.2
|
334
|
+
type: :development
|
335
|
+
prerelease: false
|
336
|
+
version_requirements: !ruby/object:Gem::Requirement
|
337
|
+
requirements:
|
338
|
+
- - "~>"
|
339
|
+
- !ruby/object:Gem::Version
|
340
|
+
version: 3.4.2
|
327
341
|
- !ruby/object:Gem::Dependency
|
328
342
|
name: standard
|
329
343
|
requirement: !ruby/object:Gem::Requirement
|
@@ -380,20 +394,6 @@ dependencies:
|
|
380
394
|
- - "~>"
|
381
395
|
- !ruby/object:Gem::Version
|
382
396
|
version: '5.1'
|
383
|
-
- !ruby/object:Gem::Dependency
|
384
|
-
name: sprockets-rails
|
385
|
-
requirement: !ruby/object:Gem::Requirement
|
386
|
-
requirements:
|
387
|
-
- - "~>"
|
388
|
-
- !ruby/object:Gem::Version
|
389
|
-
version: 3.4.2
|
390
|
-
type: :development
|
391
|
-
prerelease: false
|
392
|
-
version_requirements: !ruby/object:Gem::Requirement
|
393
|
-
requirements:
|
394
|
-
- - "~>"
|
395
|
-
- !ruby/object:Gem::Version
|
396
|
-
version: 3.4.2
|
397
397
|
- !ruby/object:Gem::Dependency
|
398
398
|
name: turbo-rails
|
399
399
|
requirement: !ruby/object:Gem::Requirement
|