view_component 2.56.2 → 2.58.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.
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
|