view_component 2.56.2 → 2.58.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/app/controllers/concerns/view_component/preview_actions.rb +7 -4
- data/app/helpers/preview_helper.rb +3 -3
- data/docs/CHANGELOG.md +68 -0
- data/lib/rails/generators/abstract_generator.rb +4 -4
- data/lib/view_component/base.rb +83 -22
- data/lib/view_component/collection.rb +9 -2
- data/lib/view_component/compiler.rb +23 -9
- data/lib/view_component/content_areas.rb +1 -1
- data/lib/view_component/docs_builder_component.rb +1 -1
- data/lib/view_component/engine.rb +6 -5
- data/lib/view_component/global_output_buffer.rb +4 -3
- data/lib/view_component/output_buffer_stack.rb +0 -2
- data/lib/view_component/polymorphic_slots.rb +17 -2
- data/lib/view_component/preview.rb +8 -6
- data/lib/view_component/render_component_to_string_helper.rb +1 -1
- data/lib/view_component/render_to_string_monkey_patch.rb +1 -1
- data/lib/view_component/rendering_component_helper.rb +1 -1
- data/lib/view_component/rendering_monkey_patch.rb +1 -1
- data/lib/view_component/slotable.rb +5 -6
- data/lib/view_component/slotable_v2.rb +7 -9
- data/lib/view_component/test_helpers.rb +3 -0
- data/lib/view_component/translatable.rb +9 -10
- data/lib/view_component/version.rb +2 -2
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 73dd7bae94ee1c5a5886e248924ccfea872df61e783e713c0744390d6729d128
|
4
|
+
data.tar.gz: e70c67571e32098ee5997b7912d07e65d427e265766c5caa398bcd47d06d3e55
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '080f91f8f3f6aa9e0db95a4b533643c627be1e31fe8fcd32cea979556e52a351f956a9b01000f0a4654039f2588d88fa6680107f5b94c1103fa4a5c0190953f3'
|
7
|
+
data.tar.gz: 7c4e322ca388053c13ad36ad8d79e706aede23d5a2e25d15cdadb2e2e8c6776c95a5981c5588134061534037fd89a11c859fe74110418072378ee4b14e10b8d6
|
@@ -37,21 +37,24 @@ module ViewComponent
|
|
37
37
|
opts = {}
|
38
38
|
opts[:layout] = layout if layout.present? || layout == false
|
39
39
|
opts[:locals] = locals if locals.present?
|
40
|
-
render "view_components/preview", opts
|
40
|
+
render "view_components/preview", opts
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
44
|
private
|
45
45
|
|
46
|
-
|
46
|
+
# :doc:
|
47
|
+
def default_preview_layout
|
47
48
|
ViewComponent::Base.default_preview_layout
|
48
49
|
end
|
49
50
|
|
50
|
-
|
51
|
+
# :doc:
|
52
|
+
def show_previews?
|
51
53
|
ViewComponent::Base.show_previews
|
52
54
|
end
|
53
55
|
|
54
|
-
|
56
|
+
# :doc:
|
57
|
+
def find_preview
|
55
58
|
candidates = []
|
56
59
|
params[:path].to_s.scan(%r{/|$}) { candidates << $` }
|
57
60
|
preview = candidates.detect { |candidate| ViewComponent::Preview.exists?(candidate) }
|
@@ -7,14 +7,14 @@ module PreviewHelper
|
|
7
7
|
def preview_source
|
8
8
|
return if @render_args.nil?
|
9
9
|
|
10
|
-
render "preview_source"
|
10
|
+
render "preview_source"
|
11
11
|
end
|
12
12
|
|
13
13
|
def find_template_data(lookup_context:, template_identifier:)
|
14
14
|
template = lookup_context.find_template(template_identifier)
|
15
15
|
|
16
16
|
if Rails.version.to_f >= 6.1 || template.source.present?
|
17
|
-
|
17
|
+
{
|
18
18
|
source: template.source,
|
19
19
|
prism_language_name: prism_language_name_by_template(template: template)
|
20
20
|
}
|
@@ -40,7 +40,7 @@ module PreviewHelper
|
|
40
40
|
template_source = File.read(template_file_path)
|
41
41
|
prism_language_name = prism_language_name_by_template_path(template_file_path: template_file_path)
|
42
42
|
|
43
|
-
|
43
|
+
{
|
44
44
|
source: template_source,
|
45
45
|
prism_language_name: prism_language_name
|
46
46
|
}
|
data/docs/CHANGELOG.md
CHANGED
@@ -9,6 +9,74 @@ title: Changelog
|
|
9
9
|
|
10
10
|
## main
|
11
11
|
|
12
|
+
## 2.58.0
|
13
|
+
|
14
|
+
* Switch to `standardrb`.
|
15
|
+
|
16
|
+
*Joel Hawksley*
|
17
|
+
|
18
|
+
* Add BootrAils article to resources.
|
19
|
+
|
20
|
+
*Joel Hawksley*
|
21
|
+
|
22
|
+
* Add @boardfish and @spone as maintainers.
|
23
|
+
|
24
|
+
*Joel Hawksley*, *Cameron Dutro*, *Blake Williams*
|
25
|
+
|
26
|
+
* Re-compile updated, inherited templates when class caching is disabled.
|
27
|
+
|
28
|
+
*Patrick Arnett*
|
29
|
+
|
30
|
+
* Add the latest version to the docs index.
|
31
|
+
* Improve the docs: add the versions various features were introduced in.
|
32
|
+
|
33
|
+
*Hans Lemuet*
|
34
|
+
|
35
|
+
* Update docs to reflect lack of block content support in controllers.
|
36
|
+
|
37
|
+
*Joel Hawksley*
|
38
|
+
|
39
|
+
* Prevent adding duplicates to `autoload_paths`.
|
40
|
+
|
41
|
+
*Thomas Hutterer*
|
42
|
+
|
43
|
+
* Add FreeAgent to list of companies using ViewComponent.
|
44
|
+
|
45
|
+
*Simon Fish*
|
46
|
+
|
47
|
+
* Include polymorphic slots in `ViewComponent::Base` by default.
|
48
|
+
|
49
|
+
*Cameron Dutro*
|
50
|
+
|
51
|
+
* Add per-component config option for stripping newlines from templates before compilation.
|
52
|
+
|
53
|
+
*Cameron Dutro*
|
54
|
+
|
55
|
+
* Add link to article by Matouš Borák.
|
56
|
+
|
57
|
+
*Joel Hawksley*
|
58
|
+
|
59
|
+
## 2.57.1
|
60
|
+
|
61
|
+
* Fix issue causing `NoMethodError`s when calling helper methods from components rendered as part of a collection.
|
62
|
+
* Fix syntax error in the ERB example in the polymorphic slots docs.
|
63
|
+
|
64
|
+
*Cameron Dutro*
|
65
|
+
|
66
|
+
## 2.57.0
|
67
|
+
|
68
|
+
* Add missing `require` for `Translatable` module in `Base`.
|
69
|
+
|
70
|
+
*Hans Lemuet*
|
71
|
+
|
72
|
+
* Allow anything that responds to `#render_in` to be rendered in the parent component's view context.
|
73
|
+
|
74
|
+
*Cameron Dutro*
|
75
|
+
|
76
|
+
* Fix script/release so it honors semver.
|
77
|
+
|
78
|
+
*Cameron Dutro*
|
79
|
+
|
12
80
|
## 2.56.2
|
13
81
|
|
14
82
|
* Restore removed `rendered_component`, marking it for deprecation in v3.0.0.
|
@@ -36,10 +36,10 @@ module ViewComponent
|
|
36
36
|
|
37
37
|
def stimulus_controller
|
38
38
|
if options["stimulus"]
|
39
|
-
File.join(destination_directory, destination_file_name)
|
40
|
-
sub("#{component_path}/", "")
|
41
|
-
|
42
|
-
gsub("/", "--")
|
39
|
+
File.join(destination_directory, destination_file_name)
|
40
|
+
.sub("#{component_path}/", "")
|
41
|
+
.tr("_", "-")
|
42
|
+
.gsub("/", "--")
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
data/lib/view_component/base.rb
CHANGED
@@ -9,12 +9,14 @@ require "view_component/polymorphic_slots"
|
|
9
9
|
require "view_component/previewable"
|
10
10
|
require "view_component/slotable"
|
11
11
|
require "view_component/slotable_v2"
|
12
|
+
require "view_component/translatable"
|
12
13
|
require "view_component/with_content_helper"
|
13
14
|
|
14
15
|
module ViewComponent
|
15
16
|
class Base < ActionView::Base
|
16
17
|
include ActiveSupport::Configurable
|
17
18
|
include ViewComponent::ContentAreas
|
19
|
+
include ViewComponent::PolymorphicSlots
|
18
20
|
include ViewComponent::Previewable
|
19
21
|
include ViewComponent::SlotableV2
|
20
22
|
include ViewComponent::Translatable
|
@@ -30,8 +32,25 @@ module ViewComponent
|
|
30
32
|
class_attribute :content_areas
|
31
33
|
self.content_areas = [] # class_attribute:default doesn't work until Rails 5.2
|
32
34
|
|
35
|
+
# Config option that strips trailing whitespace in templates before compiling them.
|
36
|
+
class_attribute :__vc_strip_trailing_whitespace, instance_accessor: false, instance_predicate: false
|
37
|
+
self.__vc_strip_trailing_whitespace = false # class_attribute:default doesn't work until Rails 5.2
|
38
|
+
|
33
39
|
attr_accessor :__vc_original_view_context
|
34
40
|
|
41
|
+
# Components render in their own view context. Helpers and other functionality
|
42
|
+
# require a reference to the original Rails view context, an instance of
|
43
|
+
# `ActionView::Base`. Use this method to set a reference to the original
|
44
|
+
# view context. Objects that implement this method will render in the component's
|
45
|
+
# view context, while objects that don't will render in the original view context
|
46
|
+
# so helpers, etc work as expected.
|
47
|
+
#
|
48
|
+
# @param view_context [ActionView::Base] The original view context.
|
49
|
+
# @return [void]
|
50
|
+
def set_original_view_context(view_context)
|
51
|
+
self.__vc_original_view_context = view_context
|
52
|
+
end
|
53
|
+
|
35
54
|
# EXPERIMENTAL: This API is experimental and may be removed at any time.
|
36
55
|
# Hook for allowing components to do work as part of the compilation process.
|
37
56
|
#
|
@@ -113,24 +132,27 @@ module ViewComponent
|
|
113
132
|
@current_template = old_current_template
|
114
133
|
end
|
115
134
|
|
135
|
+
# @private
|
116
136
|
def perform_render
|
117
137
|
render_template_for(@__vc_variant).to_s + _output_postamble
|
118
138
|
end
|
119
139
|
|
120
140
|
# Subclass components that call `super` inside their template code will cause a
|
121
|
-
# double render if they
|
141
|
+
# double render if they emit the result:
|
122
142
|
#
|
143
|
+
# ```erb
|
123
144
|
# <%= super %> # double-renders
|
124
|
-
#
|
125
145
|
# <% super %> # does not double-render
|
146
|
+
# ```
|
126
147
|
#
|
127
|
-
# Calls `super`, returning nil to avoid rendering the result twice.
|
148
|
+
# Calls `super`, returning `nil` to avoid rendering the result twice.
|
128
149
|
def render_parent
|
129
150
|
mtd = @__vc_variant ? "call_#{@__vc_variant}" : "call"
|
130
151
|
method(mtd).super_method.call
|
131
152
|
nil
|
132
153
|
end
|
133
154
|
|
155
|
+
# @private
|
134
156
|
# :nocov:
|
135
157
|
def render_template_for(variant = nil)
|
136
158
|
# Force compilation here so the compiler always redefines render_template_for.
|
@@ -172,7 +194,8 @@ module ViewComponent
|
|
172
194
|
end
|
173
195
|
|
174
196
|
# @private
|
175
|
-
def initialize(*)
|
197
|
+
def initialize(*)
|
198
|
+
end
|
176
199
|
|
177
200
|
# Re-use original view_context if we're not rendering a component.
|
178
201
|
#
|
@@ -182,8 +205,8 @@ module ViewComponent
|
|
182
205
|
#
|
183
206
|
# @private
|
184
207
|
def render(options = {}, args = {}, &block)
|
185
|
-
if options.
|
186
|
-
options.__vc_original_view_context
|
208
|
+
if options.respond_to?(:set_original_view_context)
|
209
|
+
options.set_original_view_context(self.__vc_original_view_context)
|
187
210
|
super
|
188
211
|
else
|
189
212
|
__vc_original_view_context.render(options, args, &block)
|
@@ -300,7 +323,9 @@ module ViewComponent
|
|
300
323
|
|
301
324
|
# Set the controller used for testing components:
|
302
325
|
#
|
303
|
-
#
|
326
|
+
# ```ruby
|
327
|
+
# config.view_component.test_controller = "MyTestController"
|
328
|
+
# ```
|
304
329
|
#
|
305
330
|
# Defaults to ApplicationController. Can also be configured on a per-test
|
306
331
|
# basis using `with_controller_class`.
|
@@ -310,13 +335,17 @@ module ViewComponent
|
|
310
335
|
|
311
336
|
# Set if render monkey patches should be included or not in Rails <6.1:
|
312
337
|
#
|
313
|
-
#
|
338
|
+
# ```ruby
|
339
|
+
# config.view_component.render_monkey_patch_enabled = false
|
340
|
+
# ```
|
314
341
|
#
|
315
342
|
mattr_accessor :render_monkey_patch_enabled, instance_writer: false, default: true
|
316
343
|
|
317
344
|
# Path for component files
|
318
345
|
#
|
319
|
-
#
|
346
|
+
# ```ruby
|
347
|
+
# config.view_component.view_component_path = "app/my_components"
|
348
|
+
# ```
|
320
349
|
#
|
321
350
|
# Defaults to `app/components`.
|
322
351
|
#
|
@@ -324,7 +353,9 @@ module ViewComponent
|
|
324
353
|
|
325
354
|
# Parent class for generated components
|
326
355
|
#
|
327
|
-
#
|
356
|
+
# ```ruby
|
357
|
+
# config.view_component.component_parent_class = "MyBaseComponent"
|
358
|
+
# ```
|
328
359
|
#
|
329
360
|
# Defaults to nil. If this is falsy, generators will use
|
330
361
|
# "ApplicationComponent" if defined, "ViewComponent::Base" otherwise.
|
@@ -340,25 +371,33 @@ module ViewComponent
|
|
340
371
|
#
|
341
372
|
# Always generate a component with a sidecar directory:
|
342
373
|
#
|
343
|
-
#
|
374
|
+
# ```ruby
|
375
|
+
# config.view_component.generate.sidecar = true
|
376
|
+
# ```
|
344
377
|
#
|
345
378
|
# #### #stimulus_controller
|
346
379
|
#
|
347
380
|
# Always generate a Stimulus controller alongside the component:
|
348
381
|
#
|
349
|
-
#
|
382
|
+
# ```ruby
|
383
|
+
# config.view_component.generate.stimulus_controller = true
|
384
|
+
# ```
|
350
385
|
#
|
351
386
|
# #### #locale
|
352
387
|
#
|
353
388
|
# Always generate translations file alongside the component:
|
354
389
|
#
|
355
|
-
#
|
390
|
+
# ```ruby
|
391
|
+
# config.view_component.generate.locale = true
|
392
|
+
# ```
|
356
393
|
#
|
357
394
|
# #### #distinct_locale_files
|
358
395
|
#
|
359
396
|
# Always generate as many translations files as available locales:
|
360
397
|
#
|
361
|
-
#
|
398
|
+
# ```ruby
|
399
|
+
# config.view_component.generate.distinct_locale_files = true
|
400
|
+
# ```
|
362
401
|
#
|
363
402
|
# One file will be generated for each configured `I18n.available_locales`,
|
364
403
|
# falling back to `[:en]` when no `available_locales` is defined.
|
@@ -367,7 +406,9 @@ module ViewComponent
|
|
367
406
|
#
|
368
407
|
# Always generate preview alongside the component:
|
369
408
|
#
|
370
|
-
#
|
409
|
+
# ```ruby
|
410
|
+
# config.view_component.generate.preview = true
|
411
|
+
# ```
|
371
412
|
#
|
372
413
|
# Defaults to `false`.
|
373
414
|
mattr_accessor :generate, instance_writer: false, default: ActiveSupport::OrderedOptions.new(false)
|
@@ -421,7 +462,9 @@ module ViewComponent
|
|
421
462
|
|
422
463
|
# Render a component for each element in a collection ([documentation](/guide/collections)):
|
423
464
|
#
|
424
|
-
#
|
465
|
+
# ```ruby
|
466
|
+
# render(ProductsComponent.with_collection(@products, foo: :bar))
|
467
|
+
# ```
|
425
468
|
#
|
426
469
|
# @param collection [Enumerable] A list of items to pass the ViewComponent one at a time.
|
427
470
|
# @param args [Arguments] Arguments to pass to the ViewComponent every time.
|
@@ -517,13 +560,35 @@ module ViewComponent
|
|
517
560
|
|
518
561
|
# Set the parameter name used when rendering elements of a collection ([documentation](/guide/collections)):
|
519
562
|
#
|
520
|
-
#
|
563
|
+
# ```ruby
|
564
|
+
# with_collection_parameter :item
|
565
|
+
# ```
|
521
566
|
#
|
522
567
|
# @param parameter [Symbol] The parameter name used when rendering elements of a collection.
|
523
568
|
def with_collection_parameter(parameter)
|
524
569
|
@provided_collection_parameter = parameter
|
525
570
|
end
|
526
571
|
|
572
|
+
# Strips trailing whitespace from templates before compiling them.
|
573
|
+
#
|
574
|
+
# ```ruby
|
575
|
+
# class MyComponent < ViewComponent::Base
|
576
|
+
# strip_trailing_whitespace
|
577
|
+
# end
|
578
|
+
# ```
|
579
|
+
#
|
580
|
+
# @param value [Boolean] Whether or not to strip newlines.
|
581
|
+
def strip_trailing_whitespace(value = true)
|
582
|
+
self.__vc_strip_trailing_whitespace = value
|
583
|
+
end
|
584
|
+
|
585
|
+
# Whether trailing whitespace will be stripped before compilation.
|
586
|
+
#
|
587
|
+
# @return [Boolean]
|
588
|
+
def strip_trailing_whitespace?
|
589
|
+
__vc_strip_trailing_whitespace
|
590
|
+
end
|
591
|
+
|
527
592
|
# Ensure the component initializer accepts the
|
528
593
|
# collection parameter. By default, we don't
|
529
594
|
# validate that the default parameter name
|
@@ -571,11 +636,7 @@ module ViewComponent
|
|
571
636
|
|
572
637
|
# @private
|
573
638
|
def collection_parameter
|
574
|
-
|
575
|
-
provided_collection_parameter
|
576
|
-
else
|
577
|
-
name && name.demodulize.underscore.chomp("_component").to_sym
|
578
|
-
end
|
639
|
+
provided_collection_parameter || name && name.demodulize.underscore.chomp("_component").to_sym
|
579
640
|
end
|
580
641
|
|
581
642
|
# @private
|
@@ -10,10 +10,17 @@ module ViewComponent
|
|
10
10
|
delegate :format, to: :component
|
11
11
|
delegate :size, to: :@collection
|
12
12
|
|
13
|
+
attr_accessor :__vc_original_view_context
|
14
|
+
|
15
|
+
def set_original_view_context(view_context)
|
16
|
+
self.__vc_original_view_context = view_context
|
17
|
+
end
|
18
|
+
|
13
19
|
def render_in(view_context, &block)
|
14
20
|
components.map do |component|
|
21
|
+
component.set_original_view_context(__vc_original_view_context)
|
15
22
|
component.render_in(view_context, &block)
|
16
|
-
end.join.html_safe
|
23
|
+
end.join.html_safe
|
17
24
|
end
|
18
25
|
|
19
26
|
def components
|
@@ -54,7 +61,7 @@ module ViewComponent
|
|
54
61
|
end
|
55
62
|
|
56
63
|
def component_options(item, iterator)
|
57
|
-
item_options = {
|
64
|
+
item_options = {component.collection_parameter => item}
|
58
65
|
item_options[component.collection_counter_parameter] = iterator.index + 1 if component.counter_argument_present?
|
59
66
|
item_options[component.collection_iteration_parameter] = iterator.dup if component.iteration_argument_present?
|
60
67
|
|
@@ -31,6 +31,8 @@ module ViewComponent
|
|
31
31
|
return if compiled? && !force
|
32
32
|
return if component_class == ViewComponent::Base
|
33
33
|
|
34
|
+
component_class.superclass.compile(raise_errors: raise_errors) if should_compile_superclass?
|
35
|
+
|
34
36
|
with_lock do
|
35
37
|
subclass_instance_methods = component_class.instance_methods(false)
|
36
38
|
|
@@ -68,11 +70,13 @@ module ViewComponent
|
|
68
70
|
component_class.send(:remove_method, method_name.to_sym)
|
69
71
|
end
|
70
72
|
|
73
|
+
# rubocop:disable Style/EvalWithLocation
|
71
74
|
component_class.class_eval <<-RUBY, template[:path], 0
|
72
75
|
def #{method_name}
|
73
76
|
#{compiled_template(template[:path])}
|
74
77
|
end
|
75
78
|
RUBY
|
79
|
+
# rubocop:enable Style/EvalWithLocation
|
76
80
|
end
|
77
81
|
|
78
82
|
define_render_template_for
|
@@ -151,15 +155,15 @@ module ViewComponent
|
|
151
155
|
end
|
152
156
|
|
153
157
|
invalid_variants =
|
154
|
-
templates
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
158
|
+
templates
|
159
|
+
.group_by { |template| template[:variant] }
|
160
|
+
.map { |variant, grouped| variant if grouped.length > 1 }
|
161
|
+
.compact
|
162
|
+
.sort
|
159
163
|
|
160
164
|
unless invalid_variants.empty?
|
161
165
|
errors <<
|
162
|
-
"More than one template found for #{
|
166
|
+
"More than one template found for #{"variant".pluralize(invalid_variants.count)} " \
|
163
167
|
"#{invalid_variants.map { |v| "'#{v}'" }.to_sentence} in #{component_class}. " \
|
164
168
|
"There can only be one template file per variant."
|
165
169
|
end
|
@@ -177,8 +181,8 @@ module ViewComponent
|
|
177
181
|
count = duplicate_template_file_and_inline_variant_calls.count
|
178
182
|
|
179
183
|
errors <<
|
180
|
-
"Template #{
|
181
|
-
"found for #{
|
184
|
+
"Template #{"file".pluralize(count)} and inline render #{"method".pluralize(count)} " \
|
185
|
+
"found for #{"variant".pluralize(count)} " \
|
182
186
|
"#{duplicate_template_file_and_inline_variant_calls.map { |v| "'#{v}'" }.to_sentence} " \
|
183
187
|
"in #{component_class}. " \
|
184
188
|
"There can only be a template file or inline render method per variant."
|
@@ -236,8 +240,9 @@ module ViewComponent
|
|
236
240
|
end
|
237
241
|
|
238
242
|
def compiled_template(file_path)
|
239
|
-
handler = ActionView::Template.handler_for_extension(File.extname(file_path).
|
243
|
+
handler = ActionView::Template.handler_for_extension(File.extname(file_path).delete("."))
|
240
244
|
template = File.read(file_path)
|
245
|
+
template.rstrip! if component_class.strip_trailing_whitespace?
|
241
246
|
|
242
247
|
if handler.method(:call).parameters.length > 1
|
243
248
|
handler.call(component_class, template)
|
@@ -259,5 +264,14 @@ module ViewComponent
|
|
259
264
|
"call"
|
260
265
|
end
|
261
266
|
end
|
267
|
+
|
268
|
+
def should_compile_superclass?
|
269
|
+
development? &&
|
270
|
+
templates.empty? &&
|
271
|
+
!(
|
272
|
+
component_class.instance_methods(false).include?(:call) ||
|
273
|
+
component_class.private_instance_methods(false).include?(:call)
|
274
|
+
)
|
275
|
+
end
|
262
276
|
end
|
263
277
|
end
|
@@ -28,7 +28,7 @@ module ViewComponent
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def types
|
31
|
-
" → [#{@method.tag(:return).types.join(
|
31
|
+
" → [#{@method.tag(:return).types.join(",")}]" if @method.tag(:return)&.types && show_types?
|
32
32
|
end
|
33
33
|
|
34
34
|
def signature_or_name
|
@@ -77,7 +77,8 @@ module ViewComponent
|
|
77
77
|
options = app.config.view_component
|
78
78
|
|
79
79
|
if options.show_previews && !options.preview_paths.empty?
|
80
|
-
ActiveSupport::Dependencies.autoload_paths
|
80
|
+
paths_to_add = options.preview_paths - ActiveSupport::Dependencies.autoload_paths
|
81
|
+
ActiveSupport::Dependencies.autoload_paths.concat(paths_to_add) if paths_to_add.any?
|
81
82
|
end
|
82
83
|
end
|
83
84
|
|
@@ -133,10 +134,10 @@ module ViewComponent
|
|
133
134
|
|
134
135
|
initializer "compiler mode" do |app|
|
135
136
|
ViewComponent::Compiler.mode = if Rails.env.development? || Rails.env.test?
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
137
|
+
ViewComponent::Compiler::DEVELOPMENT_MODE
|
138
|
+
else
|
139
|
+
ViewComponent::Compiler::PRODUCTION_MODE
|
140
|
+
end
|
140
141
|
end
|
141
142
|
|
142
143
|
config.after_initialize do |app|
|
@@ -34,13 +34,14 @@ module ViewComponent
|
|
34
34
|
def with_output_buffer(buf = nil)
|
35
35
|
unless buf
|
36
36
|
buf = ActionView::OutputBuffer.new
|
37
|
+
# rubocop:disable Style/SafeNavigation
|
37
38
|
if output_buffer && output_buffer.respond_to?(:encoding)
|
38
39
|
buf.force_encoding(output_buffer.encoding)
|
39
40
|
end
|
41
|
+
# rubocop:enable Style/SafeNavigation
|
40
42
|
end
|
41
43
|
|
42
44
|
output_buffer.push(buf)
|
43
|
-
result = nil
|
44
45
|
|
45
46
|
begin
|
46
47
|
yield
|
@@ -65,13 +66,13 @@ module ViewComponent
|
|
65
66
|
def with_output_buffer(buf = nil)
|
66
67
|
unless buf
|
67
68
|
buf = ActionView::OutputBuffer.new
|
69
|
+
# rubocop:disable Style/SafeNavigation
|
68
70
|
if @output_buffer && @output_buffer.respond_to?(:encoding)
|
69
71
|
buf.force_encoding(@output_buffer.encoding)
|
70
72
|
end
|
73
|
+
# rubocop:enable Style/SafeNavigation
|
71
74
|
end
|
72
75
|
|
73
|
-
result = nil
|
74
|
-
|
75
76
|
if @output_buffer.is_a?(OutputBufferStack)
|
76
77
|
@output_buffer.push(buf)
|
77
78
|
|
@@ -5,6 +5,17 @@ module ViewComponent
|
|
5
5
|
# In older rails versions, using a concern isn't a good idea here because they appear to not work with
|
6
6
|
# Module#prepend and class methods.
|
7
7
|
def self.included(base)
|
8
|
+
if base != ViewComponent::Base
|
9
|
+
# :nocov:
|
10
|
+
location = Kernel.caller_locations(1, 1)[0]
|
11
|
+
|
12
|
+
warn(
|
13
|
+
"warning: ViewComponent::PolymorphicSlots is now included in ViewComponent::Base by default "\
|
14
|
+
"and can be removed from #{location.path}:#{location.lineno}"
|
15
|
+
)
|
16
|
+
# :nocov:
|
17
|
+
end
|
18
|
+
|
8
19
|
base.singleton_class.prepend(ClassMethods)
|
9
20
|
base.include(InstanceMethods)
|
10
21
|
end
|
@@ -45,8 +56,12 @@ module ViewComponent
|
|
45
56
|
"#{slot_name}_#{poly_type}"
|
46
57
|
end
|
47
58
|
|
48
|
-
# Deprecated: Will be removed in 3.0
|
49
59
|
define_method(setter_name) do |*args, &block|
|
60
|
+
ViewComponent::Deprecation.warn(
|
61
|
+
"polymorphic slot setters like `#{setter_name}` are deprecated and will be removed in"\
|
62
|
+
"ViewComponent v3.0.0.\n\nUse `with_#{setter_name}` instead."
|
63
|
+
)
|
64
|
+
|
50
65
|
set_polymorphic_slot(slot_name, poly_type, *args, &block)
|
51
66
|
end
|
52
67
|
ruby2_keywords(setter_name.to_sym) if respond_to?(:ruby2_keywords, true)
|
@@ -57,7 +72,7 @@ module ViewComponent
|
|
57
72
|
ruby2_keywords(:"with_#{setter_name}") if respond_to?(:ruby2_keywords, true)
|
58
73
|
end
|
59
74
|
|
60
|
-
|
75
|
+
registered_slots[slot_name] = {
|
61
76
|
collection: collection,
|
62
77
|
renderable_hash: renderable_hash
|
63
78
|
}
|
@@ -14,7 +14,7 @@ module ViewComponent # :nodoc:
|
|
14
14
|
block: block,
|
15
15
|
component: component,
|
16
16
|
locals: {},
|
17
|
-
template: "view_components/preview"
|
17
|
+
template: "view_components/preview"
|
18
18
|
}
|
19
19
|
end
|
20
20
|
|
@@ -66,10 +66,12 @@ module ViewComponent # :nodoc:
|
|
66
66
|
name.chomp("Preview").underscore
|
67
67
|
end
|
68
68
|
|
69
|
+
# rubocop:disable Style/TrivialAccessors
|
69
70
|
# Setter for layout name.
|
70
71
|
def layout(layout_name)
|
71
72
|
@layout = layout_name
|
72
73
|
end
|
74
|
+
# rubocop:enable Style/TrivialAccessors
|
73
75
|
|
74
76
|
# Returns the relative path (from preview_path) to the preview example template if the template exists
|
75
77
|
def preview_example_template_path(example)
|
@@ -87,15 +89,15 @@ module ViewComponent # :nodoc:
|
|
87
89
|
end
|
88
90
|
|
89
91
|
path = Dir["#{preview_path}/#{preview_name}_preview/#{example}.html.*"].first
|
90
|
-
Pathname.new(path)
|
91
|
-
relative_path_from(Pathname.new(preview_path))
|
92
|
-
to_s
|
93
|
-
sub(/\..*$/, "")
|
92
|
+
Pathname.new(path)
|
93
|
+
.relative_path_from(Pathname.new(preview_path))
|
94
|
+
.to_s
|
95
|
+
.sub(/\..*$/, "")
|
94
96
|
end
|
95
97
|
|
96
98
|
# Returns the method body for the example from the preview file.
|
97
99
|
def preview_source(example)
|
98
|
-
source =
|
100
|
+
source = instance_method(example.to_sym).source.split("\n")
|
99
101
|
source[1...(source.size - 1)].join("\n")
|
100
102
|
end
|
101
103
|
|
@@ -4,7 +4,7 @@ module ViewComponent
|
|
4
4
|
module RenderingMonkeyPatch # :nodoc:
|
5
5
|
def render(options = {}, args = {})
|
6
6
|
if options.respond_to?(:render_in)
|
7
|
-
self.response_body = options.render_in(
|
7
|
+
self.response_body = options.render_in(view_context)
|
8
8
|
else
|
9
9
|
super
|
10
10
|
end
|
@@ -30,7 +30,7 @@ module ViewComponent
|
|
30
30
|
|
31
31
|
slot_names.each do |slot_name|
|
32
32
|
# Ensure slot_name isn't already declared
|
33
|
-
if
|
33
|
+
if slots.key?(slot_name)
|
34
34
|
raise ArgumentError.new("#{slot_name} slot declared multiple times")
|
35
35
|
end
|
36
36
|
|
@@ -73,7 +73,7 @@ module ViewComponent
|
|
73
73
|
class_name = "ViewComponent::Slot" unless class_name.present?
|
74
74
|
|
75
75
|
# Register the slot on the component
|
76
|
-
|
76
|
+
slots[slot_name] = {
|
77
77
|
class_name: class_name,
|
78
78
|
instance_variable_name: instance_variable_name,
|
79
79
|
collection: collection
|
@@ -84,7 +84,7 @@ module ViewComponent
|
|
84
84
|
def inherited(child)
|
85
85
|
# Clone slot configuration into child class
|
86
86
|
# see #test_slots_pollution
|
87
|
-
child.slots =
|
87
|
+
child.slots = slots.clone
|
88
88
|
|
89
89
|
super
|
90
90
|
end
|
@@ -106,7 +106,7 @@ module ViewComponent
|
|
106
106
|
#
|
107
107
|
def slot(slot_name, **args, &block)
|
108
108
|
# Raise ArgumentError if `slot` doesn't exist
|
109
|
-
unless slots.
|
109
|
+
unless slots.key?(slot_name)
|
110
110
|
raise ArgumentError.new "Unknown slot '#{slot_name}' - expected one of '#{slots.keys}'"
|
111
111
|
end
|
112
112
|
|
@@ -123,8 +123,7 @@ module ViewComponent
|
|
123
123
|
slot_instance = args.present? ? slot_class.new(**args) : slot_class.new
|
124
124
|
|
125
125
|
# Capture block and assign to slot_instance#content
|
126
|
-
|
127
|
-
slot_instance.content = view_context.capture(&block).to_s.strip.html_safe if block_given?
|
126
|
+
slot_instance.content = view_context.capture(&block).to_s.strip.html_safe if block
|
128
127
|
|
129
128
|
if slot[:collection]
|
130
129
|
# Initialize instance variable as an empty array
|
@@ -9,7 +9,7 @@ module ViewComponent
|
|
9
9
|
|
10
10
|
RESERVED_NAMES = {
|
11
11
|
singular: %i[content render].freeze,
|
12
|
-
plural: %i[contents renders].freeze
|
12
|
+
plural: %i[contents renders].freeze
|
13
13
|
}.freeze
|
14
14
|
|
15
15
|
# Setup component slot state
|
@@ -190,20 +190,20 @@ module ViewComponent
|
|
190
190
|
# Clone slot configuration into child class
|
191
191
|
# see #test_slots_pollution
|
192
192
|
def inherited(child)
|
193
|
-
child.registered_slots =
|
193
|
+
child.registered_slots = registered_slots.clone
|
194
194
|
super
|
195
195
|
end
|
196
196
|
|
197
197
|
private
|
198
198
|
|
199
199
|
def register_slot(slot_name, **kwargs)
|
200
|
-
|
200
|
+
registered_slots[slot_name] = define_slot(slot_name, **kwargs)
|
201
201
|
end
|
202
202
|
|
203
203
|
def define_slot(slot_name, collection:, callable:)
|
204
204
|
# Setup basic slot data
|
205
205
|
slot = {
|
206
|
-
collection: collection
|
206
|
+
collection: collection
|
207
207
|
}
|
208
208
|
return slot unless callable
|
209
209
|
|
@@ -254,7 +254,7 @@ module ViewComponent
|
|
254
254
|
end
|
255
255
|
|
256
256
|
def raise_if_slot_registered(slot_name)
|
257
|
-
if
|
257
|
+
if registered_slots.key?(slot_name)
|
258
258
|
# TODO remove? This breaks overriding slots when slots are inherited
|
259
259
|
raise ArgumentError.new(
|
260
260
|
"#{self} declares the #{slot_name} slot multiple times.\n\n" \
|
@@ -287,8 +287,6 @@ module ViewComponent
|
|
287
287
|
|
288
288
|
if slot[:collection]
|
289
289
|
[]
|
290
|
-
else
|
291
|
-
nil
|
292
290
|
end
|
293
291
|
end
|
294
292
|
|
@@ -305,7 +303,7 @@ module ViewComponent
|
|
305
303
|
# 2. Since we've to pass block content to components when calling
|
306
304
|
# `render`, evaluating the block here would require us to call
|
307
305
|
# `view_context.capture` twice, which is slower
|
308
|
-
slot.__vc_content_block = block if
|
306
|
+
slot.__vc_content_block = block if block
|
309
307
|
|
310
308
|
# If class
|
311
309
|
if slot_definition[:renderable]
|
@@ -321,7 +319,7 @@ module ViewComponent
|
|
321
319
|
# methods like `content_tag` as well as parent component state.
|
322
320
|
renderable_function = slot_definition[:renderable_function].bind(self)
|
323
321
|
renderable_value =
|
324
|
-
if
|
322
|
+
if block
|
325
323
|
renderable_function.call(*args) do |*rargs|
|
326
324
|
view_context.capture(*rargs, &block)
|
327
325
|
end
|
@@ -32,6 +32,9 @@ module ViewComponent
|
|
32
32
|
# @private
|
33
33
|
attr_reader :rendered_content
|
34
34
|
|
35
|
+
# Returns the result of a render_inline call.
|
36
|
+
#
|
37
|
+
# @return [String]
|
35
38
|
def rendered_component
|
36
39
|
ViewComponent::Deprecation.warn(
|
37
40
|
"`rendered_component` is deprecated and will be removed in v3.0.0. " \
|
@@ -9,7 +9,7 @@ module ViewComponent
|
|
9
9
|
module Translatable
|
10
10
|
extend ActiveSupport::Concern
|
11
11
|
|
12
|
-
HTML_SAFE_TRANSLATION_KEY = /(?:_|\b)html\z
|
12
|
+
HTML_SAFE_TRANSLATION_KEY = /(?:_|\b)html\z/
|
13
13
|
|
14
14
|
included do
|
15
15
|
class_attribute :i18n_backend, instance_writer: false, instance_predicate: false
|
@@ -23,14 +23,13 @@ module ViewComponent
|
|
23
23
|
def build_i18n_backend
|
24
24
|
return if CompileCache.compiled? self
|
25
25
|
|
26
|
-
if (translation_files = _sidecar_files(%w[yml yaml])).any?
|
27
|
-
|
26
|
+
self.i18n_backend = if (translation_files = _sidecar_files(%w[yml yaml])).any?
|
27
|
+
# Returning nil cleans up if translations file has been removed since the last compilation
|
28
|
+
|
29
|
+
I18nBackend.new(
|
28
30
|
i18n_scope: i18n_scope,
|
29
|
-
load_paths: translation_files
|
31
|
+
load_paths: translation_files
|
30
32
|
)
|
31
|
-
else
|
32
|
-
# Cleanup if translations file has been removed since the last compilation
|
33
|
-
self.i18n_backend = nil
|
34
33
|
end
|
35
34
|
end
|
36
35
|
end
|
@@ -50,7 +49,7 @@ module ViewComponent
|
|
50
49
|
|
51
50
|
def scope_data(data)
|
52
51
|
@i18n_scope.reverse_each do |part|
|
53
|
-
data = {
|
52
|
+
data = {part => data}
|
54
53
|
end
|
55
54
|
data
|
56
55
|
end
|
@@ -95,7 +94,7 @@ module ViewComponent
|
|
95
94
|
super(key, locale: locale, **options)
|
96
95
|
end
|
97
96
|
end
|
98
|
-
|
97
|
+
alias_method :t, :translate
|
99
98
|
|
100
99
|
# Exposes .i18n_scope as an instance method
|
101
100
|
def i18n_scope
|
@@ -109,7 +108,7 @@ module ViewComponent
|
|
109
108
|
# It's assumed here that objects loaded by the i18n backend will respond to `#html_safe?`.
|
110
109
|
# It's reasonable that if we're in Rails, `active_support/core_ext/string/output_safety.rb`
|
111
110
|
# will provide this to `Object`.
|
112
|
-
translation.html_safe
|
111
|
+
translation.html_safe
|
113
112
|
end
|
114
113
|
end
|
115
114
|
|
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.58.0
|
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: 2022-
|
11
|
+
date: 2022-07-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -185,19 +185,19 @@ dependencies:
|
|
185
185
|
- !ruby/object:Gem::Version
|
186
186
|
version: '13.0'
|
187
187
|
- !ruby/object:Gem::Dependency
|
188
|
-
name:
|
188
|
+
name: standard
|
189
189
|
requirement: !ruby/object:Gem::Requirement
|
190
190
|
requirements:
|
191
191
|
- - "~>"
|
192
192
|
- !ruby/object:Gem::Version
|
193
|
-
version:
|
193
|
+
version: '1'
|
194
194
|
type: :development
|
195
195
|
prerelease: false
|
196
196
|
version_requirements: !ruby/object:Gem::Requirement
|
197
197
|
requirements:
|
198
198
|
- - "~>"
|
199
199
|
- !ruby/object:Gem::Version
|
200
|
-
version:
|
200
|
+
version: '1'
|
201
201
|
- !ruby/object:Gem::Dependency
|
202
202
|
name: simplecov
|
203
203
|
requirement: !ruby/object:Gem::Requirement
|