view_component 2.63.0 → 2.66.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 +6 -10
- data/app/helpers/preview_helper.rb +2 -2
- data/app/views/view_components/preview.html.erb +2 -2
- data/docs/CHANGELOG.md +45 -0
- data/lib/rails/generators/abstract_generator.rb +3 -5
- data/lib/rails/generators/component/component_generator.rb +5 -4
- data/lib/rails/generators/locale/component_generator.rb +1 -1
- data/lib/view_component/base.rb +20 -30
- data/lib/view_component/compiler.rb +11 -5
- data/lib/view_component/config.rb +159 -0
- data/lib/view_component/engine.rb +10 -25
- data/lib/view_component/polymorphic_slots.rb +6 -4
- data/lib/view_component/render_preview_helper.rb +3 -7
- data/lib/view_component/slotable_v2.rb +35 -6
- data/lib/view_component/version.rb +1 -1
- data/lib/view_component.rb +1 -0
- metadata +31 -3
- data/lib/view_component/previewable.rb +0 -62
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 426a776552c0355ba0fb4ccc066c05a218b9998acb39489485375624b347c170
|
4
|
+
data.tar.gz: d17d69cb6e1c08fe31545eb5cf878579dd4aaf11e803790130c83ec7b4c178d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4b001cf58f8586b3e83cf8129c23d0bb5a499182189db4a99dfd747d6767f529a631eb2bf439a32f8a91dbb5861eb16ef637b514bffccacd476d577e2c5c27aa
|
7
|
+
data.tar.gz: 24d147cfbb226ff11114631721507bfed5a73fe25e1963186fe106a9c0f485596b65349457685967e7df0edea4d78841646f36683764244673e4281ff56741fd
|
@@ -10,9 +10,7 @@ module ViewComponent
|
|
10
10
|
around_action :set_locale, only: :previews
|
11
11
|
before_action :require_local!, unless: :show_previews?
|
12
12
|
|
13
|
-
if respond_to?(:content_security_policy)
|
14
|
-
content_security_policy(false)
|
15
|
-
end
|
13
|
+
content_security_policy(false) if respond_to?(:content_security_policy)
|
16
14
|
end
|
17
15
|
|
18
16
|
def index
|
@@ -45,18 +43,18 @@ module ViewComponent
|
|
45
43
|
|
46
44
|
# :doc:
|
47
45
|
def default_preview_layout
|
48
|
-
|
46
|
+
Rails.application.config.view_component.default_preview_layout
|
49
47
|
end
|
50
48
|
|
51
49
|
# :doc:
|
52
50
|
def show_previews?
|
53
|
-
|
51
|
+
Rails.application.config.view_component.show_previews
|
54
52
|
end
|
55
53
|
|
56
54
|
# :doc:
|
57
55
|
def find_preview
|
58
56
|
candidates = []
|
59
|
-
params[:path].to_s.scan(%r{/|$}) { candidates <<
|
57
|
+
params[:path].to_s.scan(%r{/|$}) { candidates << Regexp.last_match.pre_match }
|
60
58
|
preview = candidates.detect { |candidate| ViewComponent::Preview.exists?(candidate) }
|
61
59
|
|
62
60
|
if preview
|
@@ -66,10 +64,8 @@ module ViewComponent
|
|
66
64
|
end
|
67
65
|
end
|
68
66
|
|
69
|
-
def set_locale
|
70
|
-
I18n.with_locale(params[:locale] || I18n.default_locale)
|
71
|
-
yield
|
72
|
-
end
|
67
|
+
def set_locale(&block)
|
68
|
+
I18n.with_locale(params[:locale] || I18n.default_locale, &block)
|
73
69
|
end
|
74
70
|
|
75
71
|
# Returns either {} or {layout: value} depending on configuration
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module PreviewHelper
|
4
|
-
AVAILABLE_PRISM_LANGUAGES = [
|
4
|
+
AVAILABLE_PRISM_LANGUAGES = %w[ruby erb haml]
|
5
5
|
FALLBACK_LANGUAGE = "ruby"
|
6
6
|
|
7
7
|
def preview_source
|
@@ -22,7 +22,7 @@ module PreviewHelper
|
|
22
22
|
# Fetch template source via finding it through preview paths
|
23
23
|
# to accomodate source view when exclusively using templates
|
24
24
|
# for previews for Rails < 6.1.
|
25
|
-
all_template_paths =
|
25
|
+
all_template_paths = Rails.application.config.view_component.preview_paths.map do |preview_path|
|
26
26
|
Dir.glob("#{preview_path}/**/*")
|
27
27
|
end.flatten
|
28
28
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
<% if @render_args[:component] %>
|
2
|
-
<% if
|
2
|
+
<% if Rails.application.config.view_component.render_monkey_patch_enabled || Rails.version.to_f >= 6.1 %>
|
3
3
|
<%= render(@render_args[:component], @render_args[:args], &@render_args[:block]) %>
|
4
4
|
<% else %>
|
5
5
|
<%= render_component(@render_args[:component], &@render_args[:block]) %>
|
@@ -8,6 +8,6 @@
|
|
8
8
|
<%= render template: @render_args[:template], locals: @render_args[:locals] || {} %>
|
9
9
|
<% end %>
|
10
10
|
|
11
|
-
<% if
|
11
|
+
<% if Rails.application.config.view_component.show_previews_source %>
|
12
12
|
<%= preview_source %>
|
13
13
|
<% end %>
|
data/docs/CHANGELOG.md
CHANGED
@@ -9,6 +9,51 @@ title: Changelog
|
|
9
9
|
|
10
10
|
## main
|
11
11
|
|
12
|
+
## 2.66.0
|
13
|
+
|
14
|
+
* Add missing `generate.sidecar`, `generate.stimulus_controller`, `generate.locale`, `generate.distinct_locale_files`, `generate.preview` config options to `config.view_component`.
|
15
|
+
|
16
|
+
*Simon Fish*
|
17
|
+
|
18
|
+
## 2.65.0
|
19
|
+
|
20
|
+
* Raise `ArgumentError` when conflicting Slots are defined.
|
21
|
+
|
22
|
+
Before this change it was possible to define Slots with conflicting names, for example:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
class MyComponent < ViewComponent::Base
|
26
|
+
renders_one :item
|
27
|
+
renders_many :items
|
28
|
+
end
|
29
|
+
```
|
30
|
+
|
31
|
+
*Joel Hawksley*
|
32
|
+
|
33
|
+
## 2.64.0
|
34
|
+
|
35
|
+
* Add `warn_on_deprecated_slot_setter` flag to opt-in to deprecation warning.
|
36
|
+
|
37
|
+
In [v2.54.0](https://viewcomponent.org/CHANGELOG.html#2540), the Slots API was updated to require the `with_*` prefix for setting Slots. The non-`with_*` setters will be deprecated in a coming version and removed in `v3.0`.
|
38
|
+
|
39
|
+
To enable the coming deprecation warning, add `warn_on_deprecated_slot_setter`:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
class DeprecatedSlotsSetterComponent < ViewComponent::Base
|
43
|
+
warn_on_deprecated_slot_setter
|
44
|
+
end
|
45
|
+
```
|
46
|
+
|
47
|
+
*Joel Hawksley*
|
48
|
+
|
49
|
+
* Add [`m`](https://rubygems.org/gems/m) to development environment.
|
50
|
+
|
51
|
+
*Joel Hawksley*
|
52
|
+
|
53
|
+
* Fix potential deadlock scenario in the compiler's development mode.
|
54
|
+
|
55
|
+
*Blake Williams*
|
56
|
+
|
12
57
|
## 2.63.0
|
13
58
|
|
14
59
|
* Fixed typo in `renders_many` documentation.
|
@@ -3,9 +3,7 @@
|
|
3
3
|
module ViewComponent
|
4
4
|
module AbstractGenerator
|
5
5
|
def copy_view_file
|
6
|
-
unless options["inline"]
|
7
|
-
template "component.html.#{engine_name}", destination
|
8
|
-
end
|
6
|
+
template "component.html.#{engine_name}", destination unless options["inline"]
|
9
7
|
end
|
10
8
|
|
11
9
|
private
|
@@ -31,7 +29,7 @@ module ViewComponent
|
|
31
29
|
end
|
32
30
|
|
33
31
|
def component_path
|
34
|
-
|
32
|
+
Rails.application.config.view_component.view_component_path
|
35
33
|
end
|
36
34
|
|
37
35
|
def stimulus_controller
|
@@ -44,7 +42,7 @@ module ViewComponent
|
|
44
42
|
end
|
45
43
|
|
46
44
|
def sidecar?
|
47
|
-
options["sidecar"] ||
|
45
|
+
options["sidecar"] || Rails.application.config.view_component.generate.sidecar
|
48
46
|
end
|
49
47
|
end
|
50
48
|
end
|
@@ -13,11 +13,12 @@ module Rails
|
|
13
13
|
check_class_collision suffix: "Component"
|
14
14
|
|
15
15
|
class_option :inline, type: :boolean, default: false
|
16
|
-
class_option :locale, type: :boolean, default:
|
16
|
+
class_option :locale, type: :boolean, default: Rails.application.config.view_component.generate.locale
|
17
17
|
class_option :parent, type: :string, desc: "The parent class for the generated component"
|
18
|
-
class_option :preview, type: :boolean, default:
|
18
|
+
class_option :preview, type: :boolean, default: Rails.application.config.view_component.generate.preview
|
19
19
|
class_option :sidecar, type: :boolean, default: false
|
20
|
-
class_option :stimulus, type: :boolean,
|
20
|
+
class_option :stimulus, type: :boolean,
|
21
|
+
default: Rails.application.config.view_component.generate.stimulus_controller
|
21
22
|
|
22
23
|
def create_component_file
|
23
24
|
template "component.rb", File.join(component_path, class_path, "#{file_name}_component.rb")
|
@@ -40,7 +41,7 @@ module Rails
|
|
40
41
|
def parent_class
|
41
42
|
return options[:parent] if options[:parent]
|
42
43
|
|
43
|
-
|
44
|
+
Rails.application.config.view_component.component_parent_class || default_parent_class
|
44
45
|
end
|
45
46
|
|
46
47
|
def initialize_signature
|
@@ -12,7 +12,7 @@ module Locale
|
|
12
12
|
class_option :sidecar, type: :boolean, default: false
|
13
13
|
|
14
14
|
def create_locale_file
|
15
|
-
if
|
15
|
+
if Rails.application.config.view_component.generate.distinct_locale_files
|
16
16
|
I18n.available_locales.each do |locale|
|
17
17
|
create_file destination(locale), translations_hash([locale]).to_yaml
|
18
18
|
end
|
data/lib/view_component/base.rb
CHANGED
@@ -4,9 +4,9 @@ require "action_view"
|
|
4
4
|
require "active_support/configurable"
|
5
5
|
require "view_component/collection"
|
6
6
|
require "view_component/compile_cache"
|
7
|
+
require "view_component/config"
|
7
8
|
require "view_component/content_areas"
|
8
9
|
require "view_component/polymorphic_slots"
|
9
|
-
require "view_component/previewable"
|
10
10
|
require "view_component/slotable"
|
11
11
|
require "view_component/slotable_v2"
|
12
12
|
require "view_component/translatable"
|
@@ -14,10 +14,16 @@ require "view_component/with_content_helper"
|
|
14
14
|
|
15
15
|
module ViewComponent
|
16
16
|
class Base < ActionView::Base
|
17
|
-
|
17
|
+
class << self
|
18
|
+
delegate(*ViewComponent::Config.defaults.keys, to: :config)
|
19
|
+
|
20
|
+
def config
|
21
|
+
Rails.application.config.view_component
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
18
25
|
include ViewComponent::ContentAreas
|
19
26
|
include ViewComponent::PolymorphicSlots
|
20
|
-
include ViewComponent::Previewable
|
21
27
|
include ViewComponent::SlotableV2
|
22
28
|
include ViewComponent::Translatable
|
23
29
|
include ViewComponent::WithContentHelper
|
@@ -113,11 +119,9 @@ module ViewComponent
|
|
113
119
|
@current_template = self
|
114
120
|
|
115
121
|
if block && defined?(@__vc_content_set_by_with_content)
|
116
|
-
raise ArgumentError.
|
117
|
-
"It looks like a block was provided after calling `with_content` on #{self.class.name}, " \
|
122
|
+
raise ArgumentError, "It looks like a block was provided after calling `with_content` on #{self.class.name}, " \
|
118
123
|
"which means that ViewComponent doesn't know which content to use.\n\n" \
|
119
124
|
"To fix this issue, use either `with_content` or a block."
|
120
|
-
)
|
121
125
|
end
|
122
126
|
|
123
127
|
@__vc_content_evaluated = false
|
@@ -262,9 +266,7 @@ module ViewComponent
|
|
262
266
|
# @private
|
263
267
|
def format
|
264
268
|
# Ruby 2.6 throws a warning without checking `defined?`, 2.7 doesn't
|
265
|
-
if defined?(@__vc_variant)
|
266
|
-
@__vc_variant
|
267
|
-
end
|
269
|
+
@__vc_variant if defined?(@__vc_variant)
|
268
270
|
end
|
269
271
|
|
270
272
|
# Use the provided variant instead of the one determined by the current request.
|
@@ -313,11 +315,9 @@ module ViewComponent
|
|
313
315
|
# config.view_component.test_controller = "MyTestController"
|
314
316
|
# ```
|
315
317
|
#
|
316
|
-
# Defaults to ApplicationController. Can also be
|
317
|
-
# basis using `with_controller_class`.
|
318
|
+
# Defaults to `nil`. If this is falsy, `"ApplicationController"` is used. Can also be
|
319
|
+
# configured on a per-test basis using `with_controller_class`.
|
318
320
|
#
|
319
|
-
mattr_accessor :test_controller
|
320
|
-
@@test_controller = "ApplicationController"
|
321
321
|
|
322
322
|
# Set if render monkey patches should be included or not in Rails <6.1:
|
323
323
|
#
|
@@ -325,7 +325,6 @@ module ViewComponent
|
|
325
325
|
# config.view_component.render_monkey_patch_enabled = false
|
326
326
|
# ```
|
327
327
|
#
|
328
|
-
mattr_accessor :render_monkey_patch_enabled, instance_writer: false, default: true
|
329
328
|
|
330
329
|
# Path for component files
|
331
330
|
#
|
@@ -333,9 +332,8 @@ module ViewComponent
|
|
333
332
|
# config.view_component.view_component_path = "app/my_components"
|
334
333
|
# ```
|
335
334
|
#
|
336
|
-
# Defaults to `app/components
|
335
|
+
# Defaults to `nil`. If this is falsy, `app/components` is used.
|
337
336
|
#
|
338
|
-
mattr_accessor :view_component_path, instance_writer: false, default: "app/components"
|
339
337
|
|
340
338
|
# Parent class for generated components
|
341
339
|
#
|
@@ -346,7 +344,6 @@ module ViewComponent
|
|
346
344
|
# Defaults to nil. If this is falsy, generators will use
|
347
345
|
# "ApplicationComponent" if defined, "ViewComponent::Base" otherwise.
|
348
346
|
#
|
349
|
-
mattr_accessor :component_parent_class, instance_writer: false
|
350
347
|
|
351
348
|
# Configuration for generators.
|
352
349
|
#
|
@@ -397,7 +394,6 @@ module ViewComponent
|
|
397
394
|
# ```
|
398
395
|
#
|
399
396
|
# Defaults to `false`.
|
400
|
-
mattr_accessor :generate, instance_writer: false, default: ActiveSupport::OrderedOptions.new(false)
|
401
397
|
|
402
398
|
class << self
|
403
399
|
# @private
|
@@ -489,8 +485,8 @@ module ViewComponent
|
|
489
485
|
|
490
486
|
# If Rails application is loaded, add application url_helpers to the component context
|
491
487
|
# we need to check this to use this gem as a dependency
|
492
|
-
if defined?(Rails) && Rails.application
|
493
|
-
child.include Rails.application.routes.url_helpers
|
488
|
+
if defined?(Rails) && Rails.application && !(child < Rails.application.routes.url_helpers)
|
489
|
+
child.include Rails.application.routes.url_helpers
|
494
490
|
end
|
495
491
|
|
496
492
|
# Derive the source location of the component Ruby file from the call stack.
|
@@ -500,7 +496,7 @@ module ViewComponent
|
|
500
496
|
|
501
497
|
# Removes the first part of the path and the extension.
|
502
498
|
child.virtual_path = child.source_location.gsub(
|
503
|
-
|
499
|
+
/(.*#{Regexp.quote(Rails.application.config.view_component.view_component_path)})|(\.rb)/, ""
|
504
500
|
)
|
505
501
|
|
506
502
|
# Set collection parameter to the extended component
|
@@ -591,20 +587,16 @@ module ViewComponent
|
|
591
587
|
# parameters will be empty and ViewComponent will not be able to render
|
592
588
|
# the component.
|
593
589
|
if initialize_parameters.empty?
|
594
|
-
raise ArgumentError.
|
595
|
-
"The #{self} initializer is empty or invalid." \
|
590
|
+
raise ArgumentError, "The #{self} initializer is empty or invalid." \
|
596
591
|
"It must accept the parameter `#{parameter}` to render it as a collection.\n\n" \
|
597
592
|
"To fix this issue, update the initializer to accept `#{parameter}`.\n\n" \
|
598
593
|
"See https://viewcomponent.org/guide/collections.html for more information on rendering collections."
|
599
|
-
)
|
600
594
|
end
|
601
595
|
|
602
|
-
raise ArgumentError
|
603
|
-
"The initializer for #{self} doesn't accept the parameter `#{parameter}`, " \
|
596
|
+
raise ArgumentError, "The initializer for #{self} doesn't accept the parameter `#{parameter}`, " \
|
604
597
|
"which is required in order to render it as a collection.\n\n" \
|
605
598
|
"To fix this issue, update the initializer to accept `#{parameter}`.\n\n" \
|
606
599
|
"See https://viewcomponent.org/guide/collections.html for more information on rendering collections."
|
607
|
-
)
|
608
600
|
end
|
609
601
|
|
610
602
|
# Ensure the component initializer doesn't define
|
@@ -614,10 +606,8 @@ module ViewComponent
|
|
614
606
|
def validate_initialization_parameters!
|
615
607
|
return unless initialize_parameter_names.include?(RESERVED_PARAMETER)
|
616
608
|
|
617
|
-
raise ViewComponent::ComponentError
|
618
|
-
"#{self} initializer can't accept the parameter `#{RESERVED_PARAMETER}`, as it will override a " \
|
609
|
+
raise ViewComponent::ComponentError, "#{self} initializer can't accept the parameter `#{RESERVED_PARAMETER}`, as it will override a " \
|
619
610
|
"public ViewComponent method. To fix this issue, rename the parameter."
|
620
|
-
)
|
621
611
|
end
|
622
612
|
|
623
613
|
# @private
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "concurrent-ruby"
|
4
|
+
|
3
5
|
module ViewComponent
|
4
6
|
class Compiler
|
5
7
|
# Lock required to be obtained before compiling the component
|
@@ -16,7 +18,7 @@ module ViewComponent
|
|
16
18
|
|
17
19
|
def initialize(component_class)
|
18
20
|
@component_class = component_class
|
19
|
-
@__vc_compiler_lock =
|
21
|
+
@__vc_compiler_lock = Concurrent::ReadWriteLock.new
|
20
22
|
end
|
21
23
|
|
22
24
|
def compiled?
|
@@ -33,7 +35,7 @@ module ViewComponent
|
|
33
35
|
|
34
36
|
component_class.superclass.compile(raise_errors: raise_errors) if should_compile_superclass?
|
35
37
|
|
36
|
-
|
38
|
+
with_write_lock do
|
37
39
|
CompileCache.invalidate_class!(component_class)
|
38
40
|
|
39
41
|
subclass_instance_methods = component_class.instance_methods(false)
|
@@ -90,14 +92,18 @@ module ViewComponent
|
|
90
92
|
end
|
91
93
|
end
|
92
94
|
|
93
|
-
def
|
95
|
+
def with_write_lock(&block)
|
94
96
|
if development?
|
95
|
-
__vc_compiler_lock.
|
97
|
+
__vc_compiler_lock.with_write_lock(&block)
|
96
98
|
else
|
97
99
|
block.call
|
98
100
|
end
|
99
101
|
end
|
100
102
|
|
103
|
+
def with_read_lock(&block)
|
104
|
+
__vc_compiler_lock.with_read_lock(&block)
|
105
|
+
end
|
106
|
+
|
101
107
|
private
|
102
108
|
|
103
109
|
attr_reader :component_class
|
@@ -123,7 +129,7 @@ module ViewComponent
|
|
123
129
|
if development?
|
124
130
|
component_class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
125
131
|
def render_template_for(variant = nil)
|
126
|
-
self.class.compiler.
|
132
|
+
self.class.compiler.with_read_lock do
|
127
133
|
#{body}
|
128
134
|
end
|
129
135
|
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "view_component/deprecation"
|
4
|
+
|
5
|
+
module ViewComponent
|
6
|
+
class Config
|
7
|
+
class << self
|
8
|
+
# `new` without any arguments initializes the default configuration, but
|
9
|
+
# it's important to differentiate in case that's no longer the case in
|
10
|
+
# future.
|
11
|
+
alias_method :default, :new
|
12
|
+
|
13
|
+
def defaults
|
14
|
+
ActiveSupport::OrderedOptions.new.merge!({
|
15
|
+
generate: ActiveSupport::OrderedOptions.new(false),
|
16
|
+
preview_controller: "ViewComponentsController",
|
17
|
+
preview_route: "/rails/view_components",
|
18
|
+
show_previews_source: false,
|
19
|
+
instrumentation_enabled: false,
|
20
|
+
render_monkey_patch_enabled: true,
|
21
|
+
view_component_path: "app/components",
|
22
|
+
component_parent_class: nil,
|
23
|
+
show_previews: Rails.env.development? || Rails.env.test?,
|
24
|
+
preview_paths: default_preview_paths,
|
25
|
+
test_controller: "ApplicationController",
|
26
|
+
default_preview_layout: nil
|
27
|
+
})
|
28
|
+
end
|
29
|
+
|
30
|
+
# @!attribute generate
|
31
|
+
# @return [ActiveSupport::OrderedOptions]
|
32
|
+
# The subset of configuration options relating to generators.
|
33
|
+
#
|
34
|
+
# All options under this namespace default to `false` unless otherwise
|
35
|
+
# stated.
|
36
|
+
#
|
37
|
+
# #### #sidecar
|
38
|
+
#
|
39
|
+
# Always generate a component with a sidecar directory:
|
40
|
+
#
|
41
|
+
# config.view_component.generate.sidecar = true
|
42
|
+
#
|
43
|
+
# #### #stimulus_controller
|
44
|
+
#
|
45
|
+
# Always generate a Stimulus controller alongside the component:
|
46
|
+
#
|
47
|
+
# config.view_component.generate.stimulus_controller = true
|
48
|
+
#
|
49
|
+
# #### #locale
|
50
|
+
#
|
51
|
+
# Always generate translations file alongside the component:
|
52
|
+
#
|
53
|
+
# config.view_component.generate.locale = true
|
54
|
+
#
|
55
|
+
# #### #distinct_locale_files
|
56
|
+
#
|
57
|
+
# Always generate as many translations files as available locales:
|
58
|
+
#
|
59
|
+
# config.view_component.generate.distinct_locale_files = true
|
60
|
+
#
|
61
|
+
# One file will be generated for each configured `I18n.available_locales`,
|
62
|
+
# falling back to `[:en]` when no `available_locales` is defined.
|
63
|
+
#
|
64
|
+
# #### #preview
|
65
|
+
#
|
66
|
+
# Always generate a preview alongside the component:
|
67
|
+
#
|
68
|
+
# config.view_component.generate.preview = true
|
69
|
+
|
70
|
+
# @!attribute preview_controller
|
71
|
+
# @return [String]
|
72
|
+
# The controller used for previewing components.
|
73
|
+
# Defaults to `ViewComponentsController`.
|
74
|
+
|
75
|
+
# @!attribute preview_route
|
76
|
+
# @return [String]
|
77
|
+
# The entry route for component previews.
|
78
|
+
# Defaults to `"/rails/view_components"`.
|
79
|
+
|
80
|
+
# @!attribute show_previews_source
|
81
|
+
# @return [Boolean]
|
82
|
+
# Whether to display source code previews in component previews.
|
83
|
+
# Defaults to `false`.
|
84
|
+
|
85
|
+
# @!attribute instrumentation_enabled
|
86
|
+
# @return [Boolean]
|
87
|
+
# Whether ActiveSupport notifications are enabled.
|
88
|
+
# Defaults to `false`.
|
89
|
+
|
90
|
+
# @!attribute render_monkey_patch_enabled
|
91
|
+
# @return [Boolean] Whether the #render method should be monkey patched.
|
92
|
+
# If this is disabled, use `#render_component` or
|
93
|
+
# `#render_component_to_string` instead.
|
94
|
+
# Defaults to `true`.
|
95
|
+
|
96
|
+
# @!attribute view_component_path
|
97
|
+
# @return [String]
|
98
|
+
# The path in which components, their templates, and their sidecars should
|
99
|
+
# be stored.
|
100
|
+
# Defaults to `"app/components"`.
|
101
|
+
|
102
|
+
# @!attribute component_parent_class
|
103
|
+
# @return [String]
|
104
|
+
# The parent class from which generated components will inherit.
|
105
|
+
# Defaults to `nil`. If this is falsy, generators will use
|
106
|
+
# `"ApplicationComponent"` if defined, `"ViewComponent::Base"` otherwise.
|
107
|
+
|
108
|
+
# @!attribute show_previews
|
109
|
+
# @return [Boolean]
|
110
|
+
# Whether component previews are enabled.
|
111
|
+
# Defaults to `true` in development and test environments.
|
112
|
+
|
113
|
+
# @!attribute preview_paths
|
114
|
+
# @return [Array<String>]
|
115
|
+
# The locations in which component previews will be looked up.
|
116
|
+
# Defaults to `['test/component/previews']` relative to your Rails root.
|
117
|
+
|
118
|
+
# @!attribute preview_path
|
119
|
+
# @deprecated Use #preview_paths instead. Will be removed in v3.0.0.
|
120
|
+
|
121
|
+
# @!attribute test_controller
|
122
|
+
# @return [String]
|
123
|
+
# The controller used for testing components.
|
124
|
+
# Can also be configured on a per-test basis using `#with_controller_class`.
|
125
|
+
# Defaults to `ApplicationController`.
|
126
|
+
|
127
|
+
# @!attribute default_preview_layout
|
128
|
+
# @return [String]
|
129
|
+
# A custom default layout used for the previews index page and individual
|
130
|
+
# previews.
|
131
|
+
# Defaults to `nil`. If this is falsy, `"component_preview"` is used.
|
132
|
+
|
133
|
+
def default_preview_paths
|
134
|
+
return [] unless defined?(Rails.root) && Dir.exist?("#{Rails.root}/test/components/previews")
|
135
|
+
|
136
|
+
["#{Rails.root}/test/components/previews"]
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def initialize
|
141
|
+
@config = self.class.defaults
|
142
|
+
end
|
143
|
+
|
144
|
+
def preview_path
|
145
|
+
preview_paths
|
146
|
+
end
|
147
|
+
|
148
|
+
def preview_path=(new_value)
|
149
|
+
ViewComponent::Deprecation.warn("`preview_path` will be removed in v3.0.0. Use `preview_paths` instead.")
|
150
|
+
self.preview_paths = Array.wrap(new_value)
|
151
|
+
end
|
152
|
+
|
153
|
+
delegate_missing_to :config
|
154
|
+
|
155
|
+
private
|
156
|
+
|
157
|
+
attr_reader :config
|
158
|
+
end
|
159
|
+
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "rails"
|
4
|
+
require "view_component/base"
|
4
5
|
|
5
6
|
module ViewComponent
|
6
7
|
class Engine < Rails::Engine # :nodoc:
|
7
|
-
config.view_component =
|
8
|
-
config.view_component.preview_paths ||= []
|
8
|
+
config.view_component = ViewComponent::Config.default
|
9
9
|
|
10
10
|
rake_tasks do
|
11
11
|
load "view_component/rails/tasks/view_component.rake"
|
@@ -14,25 +14,20 @@ module ViewComponent
|
|
14
14
|
initializer "view_component.set_configs" do |app|
|
15
15
|
options = app.config.view_component
|
16
16
|
|
17
|
+
%i[generate preview_controller preview_route show_previews_source].each do |config_option|
|
18
|
+
options[config_option] ||= ViewComponent::Base.public_send(config_option)
|
19
|
+
end
|
20
|
+
options.instrumentation_enabled = false if options.instrumentation_enabled.nil?
|
17
21
|
options.render_monkey_patch_enabled = true if options.render_monkey_patch_enabled.nil?
|
18
22
|
options.show_previews = Rails.env.development? || Rails.env.test? if options.show_previews.nil?
|
19
|
-
options.show_previews_source ||= ViewComponent::Base.show_previews_source
|
20
23
|
options.instrumentation_enabled = false if options.instrumentation_enabled.nil?
|
21
|
-
options.preview_route ||= ViewComponent::Base.preview_route
|
22
|
-
options.preview_controller ||= ViewComponent::Base.preview_controller
|
23
24
|
|
24
25
|
if options.show_previews
|
26
|
+
# This is still necessary because when `config.view_component` is declared, `Rails.root` is unspecified.
|
25
27
|
options.preview_paths << "#{Rails.root}/test/components/previews" if defined?(Rails.root) && Dir.exist?(
|
26
28
|
"#{Rails.root}/test/components/previews"
|
27
29
|
)
|
28
30
|
|
29
|
-
if options.preview_path.present?
|
30
|
-
ViewComponent::Deprecation.warn(
|
31
|
-
"`preview_path` will be removed in v3.0.0. Use `preview_paths` instead."
|
32
|
-
)
|
33
|
-
options.preview_paths << options.preview_path
|
34
|
-
end
|
35
|
-
|
36
31
|
if options.show_previews_source
|
37
32
|
require "method_source"
|
38
33
|
|
@@ -41,10 +36,6 @@ module ViewComponent
|
|
41
36
|
end
|
42
37
|
end
|
43
38
|
end
|
44
|
-
|
45
|
-
ActiveSupport.on_load(:view_component) do
|
46
|
-
options.each { |k, v| send("#{k}=", v) if respond_to?("#{k}=") }
|
47
|
-
end
|
48
39
|
end
|
49
40
|
|
50
41
|
initializer "view_component.enable_instrumentation" do |app|
|
@@ -72,12 +63,6 @@ module ViewComponent
|
|
72
63
|
end
|
73
64
|
end
|
74
65
|
|
75
|
-
initializer "view_component.compile_config_methods" do
|
76
|
-
ActiveSupport.on_load(:view_component) do
|
77
|
-
config.compile_methods! if config.respond_to?(:compile_methods!)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
66
|
initializer "view_component.monkey_patch_render" do |app|
|
82
67
|
next if Rails.version.to_f >= 6.1 || !app.config.view_component.render_monkey_patch_enabled
|
83
68
|
|
@@ -94,7 +79,7 @@ module ViewComponent
|
|
94
79
|
end
|
95
80
|
end
|
96
81
|
|
97
|
-
initializer "view_component.include_render_component" do |
|
82
|
+
initializer "view_component.include_render_component" do |_app|
|
98
83
|
next if Rails.version.to_f >= 6.1
|
99
84
|
|
100
85
|
ActiveSupport.on_load(:action_view) do
|
@@ -116,7 +101,7 @@ module ViewComponent
|
|
116
101
|
end
|
117
102
|
end
|
118
103
|
|
119
|
-
initializer "compiler mode" do |
|
104
|
+
initializer "compiler mode" do |_app|
|
120
105
|
ViewComponent::Compiler.mode = if Rails.env.development? || Rails.env.test?
|
121
106
|
ViewComponent::Compiler::DEVELOPMENT_MODE
|
122
107
|
else
|
@@ -160,7 +145,7 @@ unless defined?(ViewComponent::Base)
|
|
160
145
|
|
161
146
|
ViewComponent::Deprecation.warn(
|
162
147
|
"This manually engine loading is deprecated and will be removed in v3.0.0. " \
|
163
|
-
|
148
|
+
'Remove `require "view_component/engine"`.'
|
164
149
|
)
|
165
150
|
|
166
151
|
require "view_component"
|
@@ -61,10 +61,12 @@ module ViewComponent
|
|
61
61
|
end
|
62
62
|
|
63
63
|
define_method(setter_name) do |*args, &block|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
64
|
+
if _warn_on_deprecated_slot_setter
|
65
|
+
ViewComponent::Deprecation.warn(
|
66
|
+
"polymorphic slot setters like `#{setter_name}` are deprecated and will be removed in " \
|
67
|
+
"ViewComponent v3.0.0.\n\nUse `with_#{setter_name}` instead."
|
68
|
+
)
|
69
|
+
end
|
68
70
|
|
69
71
|
set_polymorphic_slot(slot_name, poly_type, *args, &block)
|
70
72
|
end
|
@@ -22,9 +22,7 @@ module ViewComponent
|
|
22
22
|
def render_preview(name)
|
23
23
|
begin
|
24
24
|
preview_klass = if respond_to?(:described_class)
|
25
|
-
if described_class.nil?
|
26
|
-
raise "`render_preview` expected a described_class, but it is nil."
|
27
|
-
end
|
25
|
+
raise "`render_preview` expected a described_class, but it is nil." if described_class.nil?
|
28
26
|
|
29
27
|
"#{described_class}Preview"
|
30
28
|
else
|
@@ -32,12 +30,10 @@ module ViewComponent
|
|
32
30
|
end
|
33
31
|
preview_klass = preview_klass.constantize
|
34
32
|
rescue NameError
|
35
|
-
raise NameError.
|
36
|
-
"`render_preview` expected to find #{preview_klass}, but it does not exist."
|
37
|
-
)
|
33
|
+
raise NameError, "`render_preview` expected to find #{preview_klass}, but it does not exist."
|
38
34
|
end
|
39
35
|
|
40
|
-
previews_controller = build_controller(
|
36
|
+
previews_controller = build_controller(Rails.application.config.view_component.preview_controller.constantize)
|
41
37
|
previews_controller.request.params[:path] = "#{preview_klass.preview_name}/#{name}"
|
42
38
|
previews_controller.response = ActionDispatch::Response.new
|
43
39
|
result = previews_controller.previews
|
@@ -17,9 +17,19 @@ module ViewComponent
|
|
17
17
|
# Hash of registered Slots
|
18
18
|
class_attribute :registered_slots
|
19
19
|
self.registered_slots = {}
|
20
|
+
|
21
|
+
class_attribute :_warn_on_deprecated_slot_setter
|
22
|
+
self._warn_on_deprecated_slot_setter = false
|
20
23
|
end
|
21
24
|
|
22
25
|
class_methods do
|
26
|
+
##
|
27
|
+
# Enables deprecations coming to the Slots API in ViewComponent v3
|
28
|
+
#
|
29
|
+
def warn_on_deprecated_slot_setter
|
30
|
+
self._warn_on_deprecated_slot_setter = true
|
31
|
+
end
|
32
|
+
|
23
33
|
##
|
24
34
|
# Registers a sub-component
|
25
35
|
#
|
@@ -70,6 +80,7 @@ module ViewComponent
|
|
70
80
|
# <% end %>
|
71
81
|
def renders_one(slot_name, callable = nil)
|
72
82
|
validate_singular_slot_name(slot_name)
|
83
|
+
validate_plural_slot_name(ActiveSupport::Inflector.pluralize(slot_name).to_sym)
|
73
84
|
|
74
85
|
define_method :"with_#{slot_name}" do |*args, &block|
|
75
86
|
set_slot(slot_name, nil, *args, &block)
|
@@ -80,7 +91,13 @@ module ViewComponent
|
|
80
91
|
if args.empty? && block.nil?
|
81
92
|
get_slot(slot_name)
|
82
93
|
else
|
83
|
-
|
94
|
+
if _warn_on_deprecated_slot_setter
|
95
|
+
ViewComponent::Deprecation.warn(
|
96
|
+
"Setting a slot with `##{slot_name}` is deprecated and will be removed in ViewComponent v3.0.0. " \
|
97
|
+
"Use `#with_#{slot_name}` to set the slot instead."
|
98
|
+
)
|
99
|
+
end
|
100
|
+
|
84
101
|
set_slot(slot_name, nil, *args, &block)
|
85
102
|
end
|
86
103
|
end
|
@@ -131,16 +148,22 @@ module ViewComponent
|
|
131
148
|
# <% end %>
|
132
149
|
# <% end %>
|
133
150
|
def renders_many(slot_name, callable = nil)
|
134
|
-
validate_plural_slot_name(slot_name)
|
135
|
-
|
136
151
|
singular_name = ActiveSupport::Inflector.singularize(slot_name)
|
152
|
+
validate_plural_slot_name(slot_name)
|
153
|
+
validate_singular_slot_name(ActiveSupport::Inflector.singularize(slot_name).to_sym)
|
137
154
|
|
138
155
|
# Define setter for singular names
|
139
156
|
# for example `renders_many :items` allows fetching all tabs with
|
140
157
|
# `component.tabs` and setting a tab with `component.tab`
|
141
|
-
|
142
|
-
# Deprecated: Will remove in 3.0
|
158
|
+
|
143
159
|
define_method singular_name do |*args, &block|
|
160
|
+
if _warn_on_deprecated_slot_setter
|
161
|
+
ViewComponent::Deprecation.warn(
|
162
|
+
"Setting a slot with `##{singular_name}` is deprecated and will be removed in ViewComponent v3.0.0. " \
|
163
|
+
"Use `#with_#{singular_name}` to set the slot instead."
|
164
|
+
)
|
165
|
+
end
|
166
|
+
|
144
167
|
set_slot(slot_name, nil, *args, &block)
|
145
168
|
end
|
146
169
|
ruby2_keywords(singular_name.to_sym) if respond_to?(:ruby2_keywords, true)
|
@@ -162,7 +185,13 @@ module ViewComponent
|
|
162
185
|
if collection_args.nil? && block.nil?
|
163
186
|
get_slot(slot_name)
|
164
187
|
else
|
165
|
-
|
188
|
+
if _warn_on_deprecated_slot_setter
|
189
|
+
ViewComponent::Deprecation.warn(
|
190
|
+
"Setting a slot with `##{slot_name}` is deprecated and will be removed in ViewComponent v3.0.0. " \
|
191
|
+
"Use `#with_#{slot_name}` to set the slot instead."
|
192
|
+
)
|
193
|
+
end
|
194
|
+
|
166
195
|
collection_args.map do |args|
|
167
196
|
set_slot(slot_name, nil, **args, &block)
|
168
197
|
end
|
data/lib/view_component.rb
CHANGED
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.66.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-08-
|
11
|
+
date: 2022-08-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -44,6 +44,20 @@ dependencies:
|
|
44
44
|
- - "~>"
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '1.0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: concurrent-ruby
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '1.0'
|
47
61
|
- !ruby/object:Gem::Dependency
|
48
62
|
name: appraisal
|
49
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -142,6 +156,20 @@ dependencies:
|
|
142
156
|
- - "~>"
|
143
157
|
- !ruby/object:Gem::Version
|
144
158
|
version: '2'
|
159
|
+
- !ruby/object:Gem::Dependency
|
160
|
+
name: m
|
161
|
+
requirement: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - "~>"
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '1'
|
166
|
+
type: :development
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - "~>"
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: '1'
|
145
173
|
- !ruby/object:Gem::Dependency
|
146
174
|
name: minitest
|
147
175
|
requirement: !ruby/object:Gem::Requirement
|
@@ -329,6 +357,7 @@ files:
|
|
329
357
|
- lib/view_component/compile_cache.rb
|
330
358
|
- lib/view_component/compiler.rb
|
331
359
|
- lib/view_component/component_error.rb
|
360
|
+
- lib/view_component/config.rb
|
332
361
|
- lib/view_component/content_areas.rb
|
333
362
|
- lib/view_component/deprecation.rb
|
334
363
|
- lib/view_component/docs_builder_component.html.erb
|
@@ -338,7 +367,6 @@ files:
|
|
338
367
|
- lib/view_component/polymorphic_slots.rb
|
339
368
|
- lib/view_component/preview.rb
|
340
369
|
- lib/view_component/preview_template_error.rb
|
341
|
-
- lib/view_component/previewable.rb
|
342
370
|
- lib/view_component/rails/tasks/view_component.rake
|
343
371
|
- lib/view_component/render_component_helper.rb
|
344
372
|
- lib/view_component/render_component_to_string_helper.rb
|
@@ -1,62 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "active_support/concern"
|
4
|
-
|
5
|
-
module ViewComponent
|
6
|
-
module Previewable
|
7
|
-
extend ActiveSupport::Concern
|
8
|
-
|
9
|
-
included do
|
10
|
-
# Enable or disable component previews:
|
11
|
-
#
|
12
|
-
# config.view_component.show_previews = true
|
13
|
-
#
|
14
|
-
# Defaults to `true` in development.
|
15
|
-
#
|
16
|
-
mattr_accessor :show_previews, instance_writer: false
|
17
|
-
|
18
|
-
# Enable or disable source code previews in component previews:
|
19
|
-
#
|
20
|
-
# config.view_component.show_previews_source = true
|
21
|
-
#
|
22
|
-
# Defaults to `false`.
|
23
|
-
#
|
24
|
-
mattr_accessor :show_previews_source, instance_writer: false, default: false
|
25
|
-
|
26
|
-
# Set a custom default layout used for preview index and individual previews:
|
27
|
-
#
|
28
|
-
# config.view_component.default_preview_layout = "component_preview"
|
29
|
-
#
|
30
|
-
mattr_accessor :default_preview_layout, instance_writer: false
|
31
|
-
|
32
|
-
# Set the location of component previews:
|
33
|
-
#
|
34
|
-
# config.view_component.preview_paths << "#{Rails.root}/lib/component_previews"
|
35
|
-
#
|
36
|
-
mattr_accessor :preview_paths, instance_writer: false
|
37
|
-
|
38
|
-
# @deprecated Use `preview_paths` instead. Will be removed in v3.0.0.
|
39
|
-
mattr_accessor :preview_path, instance_writer: false
|
40
|
-
|
41
|
-
# Set the entry route for component previews:
|
42
|
-
#
|
43
|
-
# config.view_component.preview_route = "/previews"
|
44
|
-
#
|
45
|
-
# Defaults to `/rails/view_components` when `show_previews` is enabled.
|
46
|
-
#
|
47
|
-
mattr_accessor :preview_route, instance_writer: false do
|
48
|
-
"/rails/view_components"
|
49
|
-
end
|
50
|
-
|
51
|
-
# Set the controller used for previewing components:
|
52
|
-
#
|
53
|
-
# config.view_component.preview_controller = "MyPreviewController"
|
54
|
-
#
|
55
|
-
# Defaults to `ViewComponentsController`.
|
56
|
-
#
|
57
|
-
mattr_accessor :preview_controller, instance_writer: false do
|
58
|
-
"ViewComponentsController"
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|