view_component 3.23.2 → 4.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/concerns/view_component/preview_actions.rb +11 -14
- data/app/controllers/view_components_system_test_controller.rb +25 -19
- data/app/views/test_mailer/test_asset_email.html.erb +1 -0
- data/app/views/test_mailer/test_url_email.html.erb +1 -0
- data/app/views/view_components/preview.html.erb +1 -9
- data/docs/CHANGELOG.md +612 -108
- data/lib/{rails/generators → generators/view_component}/abstract_generator.rb +2 -2
- data/lib/{rails/generators → generators/view_component}/component/component_generator.rb +17 -4
- data/lib/{rails/generators → generators/view_component}/component/templates/component.rb.tt +6 -1
- data/lib/{rails/generators/erb/component_generator.rb → generators/view_component/erb/erb_generator.rb} +4 -3
- data/lib/{rails/generators/haml/component_generator.rb → generators/view_component/haml/haml_generator.rb} +3 -3
- data/lib/{rails/generators/locale/component_generator.rb → generators/view_component/locale/locale_generator.rb} +3 -3
- data/lib/{rails/generators/preview/component_generator.rb → generators/view_component/preview/preview_generator.rb} +3 -3
- data/lib/{rails/generators/rspec/component_generator.rb → generators/view_component/rspec/rspec_generator.rb} +3 -3
- data/lib/{rails/generators/slim/component_generator.rb → generators/view_component/slim/slim_generator.rb} +3 -3
- data/lib/{rails/generators/stimulus/component_generator.rb → generators/view_component/stimulus/stimulus_generator.rb} +3 -3
- data/lib/generators/view_component/tailwindcss/tailwindcss_generator.rb +11 -0
- data/lib/{rails/generators/test_unit/component_generator.rb → generators/view_component/test_unit/test_unit_generator.rb} +2 -2
- data/lib/view_component/base.rb +252 -163
- data/lib/view_component/collection.rb +33 -35
- data/lib/view_component/compiler.rb +55 -80
- data/lib/view_component/config.rb +55 -85
- data/lib/view_component/configurable.rb +19 -3
- data/lib/view_component/deprecation.rb +1 -1
- data/lib/view_component/engine.rb +46 -106
- data/lib/view_component/errors.rb +16 -34
- data/lib/view_component/inline_template.rb +4 -4
- data/lib/view_component/instrumentation.rb +21 -14
- data/lib/view_component/preview.rb +7 -12
- data/lib/view_component/request_details.rb +30 -0
- data/lib/view_component/slot.rb +7 -15
- data/lib/view_component/slotable.rb +94 -80
- data/lib/view_component/system_spec_helpers.rb +11 -0
- data/lib/view_component/system_test_helpers.rb +2 -2
- data/lib/view_component/template.rb +159 -83
- data/lib/view_component/test_helpers.rb +67 -50
- data/lib/view_component/translatable.rb +33 -32
- data/lib/view_component/version.rb +3 -3
- data/lib/view_component.rb +9 -6
- metadata +36 -556
- data/app/assets/vendor/prism.css +0 -4
- data/app/assets/vendor/prism.min.js +0 -12
- data/app/helpers/preview_helper.rb +0 -85
- data/app/views/view_components/_preview_source.html.erb +0 -17
- data/lib/rails/generators/tailwindcss/component_generator.rb +0 -11
- data/lib/view_component/capture_compatibility.rb +0 -44
- data/lib/view_component/component_error.rb +0 -6
- data/lib/view_component/rails/tasks/view_component.rake +0 -20
- data/lib/view_component/render_component_helper.rb +0 -10
- data/lib/view_component/render_component_to_string_helper.rb +0 -9
- data/lib/view_component/render_monkey_patch.rb +0 -13
- data/lib/view_component/render_to_string_monkey_patch.rb +0 -13
- data/lib/view_component/rendering_component_helper.rb +0 -9
- data/lib/view_component/rendering_monkey_patch.rb +0 -13
- data/lib/view_component/slotable_default.rb +0 -20
- data/lib/view_component/use_helpers.rb +0 -42
- /data/lib/{rails/generators → generators/view_component}/erb/templates/component.html.erb.tt +0 -0
- /data/lib/{rails/generators → generators/view_component}/haml/templates/component.html.haml.tt +0 -0
- /data/lib/{rails/generators → generators/view_component}/preview/templates/component_preview.rb.tt +0 -0
- /data/lib/{rails/generators → generators/view_component}/rspec/templates/component_spec.rb.tt +0 -0
- /data/lib/{rails/generators → generators/view_component}/slim/templates/component.html.slim.tt +0 -0
- /data/lib/{rails/generators → generators/view_component}/stimulus/templates/component_controller.js.tt +0 -0
- /data/lib/{rails/generators → generators/view_component}/stimulus/templates/component_controller.ts.tt +0 -0
- /data/lib/{rails/generators → generators/view_component}/tailwindcss/templates/component.html.erb.tt +0 -0
- /data/lib/{rails/generators → generators/view_component}/test_unit/templates/component_test.rb.tt +0 -0
|
@@ -1,53 +1,52 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "action_view/renderer/collection_renderer"
|
|
3
|
+
require "action_view/renderer/collection_renderer"
|
|
4
|
+
require "action_view/helpers/output_safety_helper"
|
|
4
5
|
|
|
5
6
|
module ViewComponent
|
|
6
7
|
class Collection
|
|
7
8
|
include Enumerable
|
|
9
|
+
include ActionView::Helpers::OutputSafetyHelper
|
|
10
|
+
|
|
8
11
|
attr_reader :component
|
|
9
12
|
|
|
10
13
|
delegate :size, to: :@collection
|
|
11
14
|
|
|
12
|
-
|
|
15
|
+
def render_in(view_context, **_, &block)
|
|
16
|
+
rendered = components.map do |component|
|
|
17
|
+
component.render_in(view_context, &block)
|
|
18
|
+
end
|
|
19
|
+
safe_join(rendered, rendered_spacer(view_context))
|
|
20
|
+
end
|
|
13
21
|
|
|
14
|
-
def
|
|
15
|
-
|
|
22
|
+
def each(&block)
|
|
23
|
+
components.each(&block)
|
|
16
24
|
end
|
|
17
25
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
26
|
+
if defined?(Rails::VERSION) && Rails::VERSION::MAJOR == 7 && Rails::VERSION::MINOR == 1
|
|
27
|
+
# Rails expects us to define `format` on all renderables,
|
|
28
|
+
# but we do not know the `format` of a ViewComponent until runtime.
|
|
29
|
+
def format
|
|
30
|
+
nil
|
|
31
|
+
end
|
|
23
32
|
end
|
|
24
33
|
|
|
25
|
-
|
|
26
|
-
return @components if defined? @components
|
|
34
|
+
private
|
|
27
35
|
|
|
36
|
+
# Always rebuild child component instances per render to avoid leaking
|
|
37
|
+
# request-scoped state from a previous render into a later one (GHSA).
|
|
38
|
+
def components
|
|
28
39
|
iterator = ActionView::PartialIteration.new(@collection.size)
|
|
29
40
|
|
|
30
|
-
component.
|
|
41
|
+
component.__vc_validate_collection_parameter!(validate_default: true)
|
|
31
42
|
|
|
32
|
-
@
|
|
33
|
-
component.new(**component_options(item, iterator)).tap do |
|
|
43
|
+
@collection.map do |item|
|
|
44
|
+
component.new(**component_options(item, iterator)).tap do |_|
|
|
34
45
|
iterator.iterate!
|
|
35
46
|
end
|
|
36
47
|
end
|
|
37
48
|
end
|
|
38
49
|
|
|
39
|
-
def each(&block)
|
|
40
|
-
components.each(&block)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# Rails expects us to define `format` on all renderables,
|
|
44
|
-
# but we do not know the `format` of a ViewComponent until runtime.
|
|
45
|
-
def format
|
|
46
|
-
nil
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
private
|
|
50
|
-
|
|
51
50
|
def initialize(component, object, spacer_component, **options)
|
|
52
51
|
@component = component
|
|
53
52
|
@collection = collection_variable(object || [])
|
|
@@ -64,20 +63,19 @@ module ViewComponent
|
|
|
64
63
|
end
|
|
65
64
|
|
|
66
65
|
def component_options(item, iterator)
|
|
67
|
-
item_options = {component.
|
|
68
|
-
item_options[component.
|
|
69
|
-
item_options[component.
|
|
66
|
+
item_options = {component.__vc_collection_parameter => item}
|
|
67
|
+
item_options[component.__vc_collection_counter_parameter] = iterator.index if component.__vc_counter_argument_present?
|
|
68
|
+
item_options[component.__vc_collection_iteration_parameter] = iterator.dup if component.__vc_iteration_argument_present?
|
|
70
69
|
|
|
71
70
|
@options.merge(item_options)
|
|
72
71
|
end
|
|
73
72
|
|
|
73
|
+
# Render the spacer through a fresh `dup` so a collection rendered multiple
|
|
74
|
+
# times always gets a clean spacer instance.
|
|
74
75
|
def rendered_spacer(view_context)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
else
|
|
79
|
-
""
|
|
80
|
-
end
|
|
76
|
+
return "" unless @spacer_component
|
|
77
|
+
|
|
78
|
+
@spacer_component.dup.render_in(view_context)
|
|
81
79
|
end
|
|
82
80
|
end
|
|
83
81
|
end
|
|
@@ -8,7 +8,7 @@ module ViewComponent
|
|
|
8
8
|
# * true (a blocking mode which ensures thread safety when redefining the `call` method for components,
|
|
9
9
|
# default in Rails development and test mode)
|
|
10
10
|
# * false(a non-blocking mode, default in Rails production mode)
|
|
11
|
-
class_attribute :
|
|
11
|
+
class_attribute :__vc_development_mode, default: false
|
|
12
12
|
|
|
13
13
|
def initialize(component)
|
|
14
14
|
@component = component
|
|
@@ -30,8 +30,8 @@ module ViewComponent
|
|
|
30
30
|
|
|
31
31
|
gather_templates
|
|
32
32
|
|
|
33
|
-
if self.class.
|
|
34
|
-
@component.superclass.
|
|
33
|
+
if self.class.__vc_development_mode && @templates.any?(&:requires_compiled_superclass?)
|
|
34
|
+
@component.superclass.__vc_compile(raise_errors: raise_errors)
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
if template_errors.present?
|
|
@@ -42,17 +42,36 @@ module ViewComponent
|
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
if raise_errors
|
|
45
|
-
@component.
|
|
46
|
-
@component.
|
|
45
|
+
@component.__vc_validate_initialization_parameters!
|
|
46
|
+
@component.__vc_validate_collection_parameter!
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
define_render_template_for
|
|
50
50
|
|
|
51
|
-
@component.
|
|
52
|
-
@component.
|
|
51
|
+
@component.__vc_register_default_slots
|
|
52
|
+
@component.__vc_build_i18n_backend
|
|
53
53
|
|
|
54
54
|
CompileCache.register(@component)
|
|
55
|
+
|
|
56
|
+
@component.after_compile
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# @param requested_details [ActionView::TemplateDetails::Requested] i.e. locales, formats, variants
|
|
61
|
+
#
|
|
62
|
+
# @return all matching compiled templates, in priority order based on the requested details from LookupContext
|
|
63
|
+
def find_templates_for(requested_details)
|
|
64
|
+
filtered_templates = @templates.select do |template|
|
|
65
|
+
template.details.matches?(requested_details)
|
|
55
66
|
end
|
|
67
|
+
|
|
68
|
+
if filtered_templates.count > 1
|
|
69
|
+
filtered_templates.sort_by! do |template|
|
|
70
|
+
template.details.sort_key_for(requested_details)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
filtered_templates
|
|
56
75
|
end
|
|
57
76
|
|
|
58
77
|
private
|
|
@@ -64,40 +83,25 @@ module ViewComponent
|
|
|
64
83
|
template.compile_to_component
|
|
65
84
|
end
|
|
66
85
|
|
|
67
|
-
|
|
68
|
-
if @templates.one?
|
|
69
|
-
@templates.first.safe_method_name_call
|
|
70
|
-
elsif (template = @templates.find(&:inline?))
|
|
71
|
-
template.safe_method_name_call
|
|
72
|
-
else
|
|
73
|
-
branches = []
|
|
74
|
-
|
|
75
|
-
@templates.each do |template|
|
|
76
|
-
conditional =
|
|
77
|
-
if template.inline_call?
|
|
78
|
-
"variant&.to_sym == #{template.variant.inspect}"
|
|
79
|
-
else
|
|
80
|
-
[
|
|
81
|
-
template.default_format? ? "(format == #{ViewComponent::Base::VC_INTERNAL_DEFAULT_FORMAT.inspect} || format.nil?)" : "format == #{template.format.inspect}",
|
|
82
|
-
template.variant.nil? ? "variant.nil?" : "variant&.to_sym == #{template.variant.inspect}"
|
|
83
|
-
].join(" && ")
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
branches << [conditional, template.safe_method_name_call]
|
|
87
|
-
end
|
|
86
|
+
@component.silence_redefinition_of_method(:render_template_for)
|
|
88
87
|
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
if @templates.one?
|
|
89
|
+
template = @templates.first
|
|
90
|
+
safe_call = template.safe_method_name_call
|
|
91
|
+
@component.define_method(:render_template_for) do |_|
|
|
92
|
+
@current_template = template
|
|
93
|
+
instance_exec(&safe_call)
|
|
94
|
+
end
|
|
95
|
+
else
|
|
96
|
+
compiler = self
|
|
97
|
+
@component.define_method(:render_template_for) do |details|
|
|
98
|
+
if (@current_template = compiler.find_templates_for(details).first)
|
|
99
|
+
instance_exec(&@current_template.safe_method_name_call)
|
|
100
|
+
else
|
|
101
|
+
raise MissingTemplateError.new(self.class.name, details)
|
|
91
102
|
end
|
|
92
|
-
out << "else\n #{templates.find { _1.variant.nil? && _1.default_format? }.safe_method_name_call}\nend"
|
|
93
103
|
end
|
|
94
|
-
|
|
95
|
-
@component.silence_redefinition_of_method(:render_template_for)
|
|
96
|
-
@component.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
97
|
-
def render_template_for(variant = nil, format = nil)
|
|
98
|
-
#{method_body}
|
|
99
104
|
end
|
|
100
|
-
RUBY
|
|
101
105
|
end
|
|
102
106
|
|
|
103
107
|
def template_errors
|
|
@@ -106,19 +110,16 @@ module ViewComponent
|
|
|
106
110
|
|
|
107
111
|
errors << "Couldn't find a template file or inline render method for #{@component}." if @templates.empty?
|
|
108
112
|
|
|
109
|
-
|
|
110
|
-
# inline call method overriding the template. We should aim to change this in v4 to instead
|
|
111
|
-
# raise an error.
|
|
112
|
-
@templates.reject(&:inline_call?)
|
|
113
|
+
@templates
|
|
113
114
|
.map { |template| [template.variant, template.format] }
|
|
114
115
|
.tally
|
|
115
116
|
.select { |_, count| count > 1 }
|
|
116
117
|
.each do |tally|
|
|
117
|
-
|
|
118
|
+
variant, this_format = tally.first
|
|
118
119
|
|
|
119
|
-
|
|
120
|
+
variant_string = " for variant `#{variant}`" if variant.present?
|
|
120
121
|
|
|
121
|
-
|
|
122
|
+
errors << "More than one #{this_format.upcase} template found#{variant_string} for #{@component}. "
|
|
122
123
|
end
|
|
123
124
|
|
|
124
125
|
default_template_types = @templates.each_with_object(Set.new) do |template, memo|
|
|
@@ -168,30 +169,18 @@ module ViewComponent
|
|
|
168
169
|
|
|
169
170
|
def gather_templates
|
|
170
171
|
@templates ||=
|
|
171
|
-
|
|
172
|
+
if @component.__vc_inline_template.present?
|
|
173
|
+
[Template::Inline.new(
|
|
174
|
+
component: @component,
|
|
175
|
+
inline_template: @component.__vc_inline_template
|
|
176
|
+
)]
|
|
177
|
+
else
|
|
178
|
+
path_parser = ActionView::Resolver::PathParser.new
|
|
172
179
|
templates = @component.sidecar_files(
|
|
173
180
|
ActionView::Template.template_handler_extensions
|
|
174
181
|
).map do |path|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
File
|
|
178
|
-
.basename(path) # "variants_component.html+mini.watch.erb"
|
|
179
|
-
.split(".")[1..-2] # ["html+mini", "watch"]
|
|
180
|
-
.join(".") # "html+mini.watch"
|
|
181
|
-
.split("+") # ["html", "mini.watch"]
|
|
182
|
-
.map(&:to_sym) # [:html, :"mini.watch"]
|
|
183
|
-
|
|
184
|
-
out = Template.new(
|
|
185
|
-
component: @component,
|
|
186
|
-
type: :file,
|
|
187
|
-
path: path,
|
|
188
|
-
lineno: 0,
|
|
189
|
-
extension: path.split(".").last,
|
|
190
|
-
this_format: this_format.to_s.split(".").last&.to_sym, # strip locale from this_format, see #2113
|
|
191
|
-
variant: variant
|
|
192
|
-
)
|
|
193
|
-
|
|
194
|
-
out
|
|
182
|
+
details = path_parser.parse(path).details
|
|
183
|
+
Template::File.new(component: @component, path: path, details: details)
|
|
195
184
|
end
|
|
196
185
|
|
|
197
186
|
component_instance_methods_on_self = @component.instance_methods(false)
|
|
@@ -201,25 +190,11 @@ module ViewComponent
|
|
|
201
190
|
).flat_map { |ancestor| ancestor.instance_methods(false).grep(/^call(_|$)/) }
|
|
202
191
|
.uniq
|
|
203
192
|
.each do |method_name|
|
|
204
|
-
templates << Template.new(
|
|
193
|
+
templates << Template::InlineCall.new(
|
|
205
194
|
component: @component,
|
|
206
|
-
type: :inline_call,
|
|
207
|
-
this_format: ViewComponent::Base::VC_INTERNAL_DEFAULT_FORMAT,
|
|
208
|
-
variant: method_name.to_s.include?("call_") ? method_name.to_s.sub("call_", "").to_sym : nil,
|
|
209
195
|
method_name: method_name,
|
|
210
196
|
defined_on_self: component_instance_methods_on_self.include?(method_name)
|
|
211
197
|
)
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
if @component.inline_template.present?
|
|
215
|
-
templates << Template.new(
|
|
216
|
-
component: @component,
|
|
217
|
-
type: :inline,
|
|
218
|
-
path: @component.inline_template.path,
|
|
219
|
-
lineno: @component.inline_template.lineno,
|
|
220
|
-
source: @component.inline_template.source.dup,
|
|
221
|
-
extension: @component.inline_template.language
|
|
222
|
-
)
|
|
223
198
|
end
|
|
224
199
|
|
|
225
200
|
templates
|
|
@@ -13,29 +13,25 @@ module ViewComponent
|
|
|
13
13
|
def defaults
|
|
14
14
|
ActiveSupport::OrderedOptions.new.merge!({
|
|
15
15
|
generate: default_generate_options,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
show_previews_source: false,
|
|
19
|
-
instrumentation_enabled: false,
|
|
20
|
-
use_deprecated_instrumentation_name: true,
|
|
21
|
-
render_monkey_patch_enabled: true,
|
|
22
|
-
view_component_path: "app/components",
|
|
23
|
-
component_parent_class: nil,
|
|
24
|
-
show_previews: Rails.env.development? || Rails.env.test?,
|
|
25
|
-
preview_paths: default_preview_paths,
|
|
26
|
-
test_controller: "ApplicationController",
|
|
27
|
-
default_preview_layout: nil,
|
|
28
|
-
capture_compatibility_patch_enabled: false
|
|
16
|
+
previews: default_previews_options,
|
|
17
|
+
instrumentation_enabled: false
|
|
29
18
|
})
|
|
30
19
|
end
|
|
31
20
|
|
|
32
21
|
# @!attribute generate
|
|
22
|
+
#
|
|
33
23
|
# @return [ActiveSupport::OrderedOptions]
|
|
34
24
|
# The subset of configuration options relating to generators.
|
|
35
25
|
#
|
|
36
26
|
# All options under this namespace default to `false` unless otherwise
|
|
37
27
|
# stated.
|
|
38
28
|
#
|
|
29
|
+
# #### `#path`
|
|
30
|
+
#
|
|
31
|
+
# Where to put generated components. Defaults to `app/components`:
|
|
32
|
+
#
|
|
33
|
+
# config.view_component.generate.path = "lib/components"
|
|
34
|
+
#
|
|
39
35
|
# #### `#sidecar`
|
|
40
36
|
#
|
|
41
37
|
# Always generate a component with a sidecar directory:
|
|
@@ -83,96 +79,58 @@ module ViewComponent
|
|
|
83
79
|
#
|
|
84
80
|
# Required when there is more than one path defined in preview_paths.
|
|
85
81
|
# Defaults to `""`. If this is blank, the generator will use
|
|
86
|
-
# `ViewComponent.config.
|
|
82
|
+
# `ViewComponent.config.previews.paths` if defined,
|
|
87
83
|
# `"test/components/previews"` otherwise
|
|
88
84
|
#
|
|
89
85
|
# #### `#use_component_path_for_rspec_tests`
|
|
90
86
|
#
|
|
91
|
-
# Whether to use
|
|
87
|
+
# Whether to use `config.generate.path` when generating new
|
|
92
88
|
# RSpec component tests:
|
|
93
89
|
#
|
|
94
90
|
# config.view_component.generate.use_component_path_for_rspec_tests = true
|
|
95
91
|
#
|
|
96
|
-
# When set to `true`, the generator will use the `
|
|
92
|
+
# When set to `true`, the generator will use the `path` to
|
|
97
93
|
# decide where to generate the new RSpec component test.
|
|
98
|
-
# For example, if the `
|
|
94
|
+
# For example, if the `path` is
|
|
99
95
|
# `app/views/components`, then the generator will create a new spec file
|
|
100
96
|
# in `spec/views/components/` rather than the default `spec/components/`.
|
|
101
97
|
|
|
102
|
-
# @!attribute
|
|
103
|
-
#
|
|
104
|
-
#
|
|
105
|
-
#
|
|
106
|
-
|
|
107
|
-
#
|
|
108
|
-
#
|
|
109
|
-
# The
|
|
110
|
-
#
|
|
111
|
-
|
|
112
|
-
#
|
|
113
|
-
#
|
|
114
|
-
#
|
|
115
|
-
# Defaults to
|
|
98
|
+
# @!attribute previews
|
|
99
|
+
#
|
|
100
|
+
# @return [ActiveSupport::OrderedOptions]
|
|
101
|
+
# The subset of configuration options relating to previews.
|
|
102
|
+
#
|
|
103
|
+
# #### `#controller`
|
|
104
|
+
#
|
|
105
|
+
# The controller used for previewing components. Defaults to `ViewComponentsController`:
|
|
106
|
+
#
|
|
107
|
+
# config.view_component.previews.controller = "MyPreviewController"
|
|
108
|
+
#
|
|
109
|
+
# #### `#route`
|
|
110
|
+
#
|
|
111
|
+
# The entry route for component previews. Defaults to `/rails/view_components`:
|
|
112
|
+
#
|
|
113
|
+
# config.view_component.previews.route = "/my_previews"
|
|
114
|
+
#
|
|
115
|
+
# #### `#enabled`
|
|
116
|
+
#
|
|
117
|
+
# Whether component previews are enabled. Defaults to `true` in development and test environments:
|
|
118
|
+
#
|
|
119
|
+
# config.view_component.previews.enabled = false
|
|
120
|
+
#
|
|
121
|
+
# #### `#default_layout`
|
|
122
|
+
#
|
|
123
|
+
# A custom default layout used for the previews index page and individual previews. Defaults to `nil`:
|
|
124
|
+
#
|
|
125
|
+
# config.view_component.previews.default_layout = "preview_layout"
|
|
126
|
+
#
|
|
116
127
|
|
|
117
128
|
# @!attribute instrumentation_enabled
|
|
129
|
+
#
|
|
118
130
|
# @return [Boolean]
|
|
119
131
|
# Whether ActiveSupport notifications are enabled.
|
|
120
132
|
# Defaults to `false`.
|
|
121
133
|
|
|
122
|
-
# @!attribute use_deprecated_instrumentation_name
|
|
123
|
-
# @return [Boolean]
|
|
124
|
-
# Whether ActiveSupport Notifications use the private name `"!render.view_component"`
|
|
125
|
-
# or are made more publicly available via `"render.view_component"`.
|
|
126
|
-
# Will be removed in next major version.
|
|
127
|
-
# Defaults to `true`.
|
|
128
|
-
|
|
129
|
-
# @!attribute render_monkey_patch_enabled
|
|
130
|
-
# @return [Boolean] Whether the #render method should be monkey patched.
|
|
131
|
-
# If this is disabled, use `#render_component` or
|
|
132
|
-
# `#render_component_to_string` instead.
|
|
133
|
-
# Defaults to `true`.
|
|
134
|
-
|
|
135
|
-
# @!attribute view_component_path
|
|
136
|
-
# @return [String]
|
|
137
|
-
# The path in which components, their templates, and their sidecars should
|
|
138
|
-
# be stored.
|
|
139
|
-
# Defaults to `"app/components"`.
|
|
140
|
-
|
|
141
|
-
# @!attribute component_parent_class
|
|
142
|
-
# @return [String]
|
|
143
|
-
# The parent class from which generated components will inherit.
|
|
144
|
-
# Defaults to `nil`. If this is falsy, generators will use
|
|
145
|
-
# `"ApplicationComponent"` if defined, `"ViewComponent::Base"` otherwise.
|
|
146
|
-
|
|
147
|
-
# @!attribute show_previews
|
|
148
|
-
# @return [Boolean]
|
|
149
|
-
# Whether component previews are enabled.
|
|
150
|
-
# Defaults to `true` in development and test environments.
|
|
151
|
-
|
|
152
|
-
# @!attribute preview_paths
|
|
153
|
-
# @return [Array<String>]
|
|
154
|
-
# The locations in which component previews will be looked up.
|
|
155
|
-
# Defaults to `['test/components/previews']` relative to your Rails root.
|
|
156
|
-
|
|
157
|
-
# @!attribute test_controller
|
|
158
|
-
# @return [String]
|
|
159
|
-
# The controller used for testing components.
|
|
160
|
-
# Can also be configured on a per-test basis using `#with_controller_class`.
|
|
161
|
-
# Defaults to `ApplicationController`.
|
|
162
|
-
|
|
163
|
-
# @!attribute default_preview_layout
|
|
164
|
-
# @return [String]
|
|
165
|
-
# A custom default layout used for the previews index page and individual
|
|
166
|
-
# previews.
|
|
167
|
-
# Defaults to `nil`. If this is falsy, `"component_preview"` is used.
|
|
168
|
-
|
|
169
|
-
# @!attribute capture_compatibility_patch_enabled
|
|
170
|
-
# @return [Boolean]
|
|
171
|
-
# Enables the experimental capture compatibility patch that makes ViewComponent
|
|
172
|
-
# compatible with forms, capture, and other built-ins.
|
|
173
|
-
# previews.
|
|
174
|
-
# Defaults to `false`.
|
|
175
|
-
|
|
176
134
|
def default_preview_paths
|
|
177
135
|
(default_rails_preview_paths + default_rails_engines_preview_paths).uniq
|
|
178
136
|
end
|
|
@@ -200,11 +158,23 @@ module ViewComponent
|
|
|
200
158
|
def default_generate_options
|
|
201
159
|
options = ActiveSupport::OrderedOptions.new(false)
|
|
202
160
|
options.preview_path = ""
|
|
161
|
+
options.path = "app/components"
|
|
162
|
+
options
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def default_previews_options
|
|
166
|
+
options = ActiveSupport::OrderedOptions.new
|
|
167
|
+
options.controller = "ViewComponentsController"
|
|
168
|
+
options.route = "/rails/view_components"
|
|
169
|
+
options.enabled = defined?(Rails.env) && (Rails.env.development? || Rails.env.test?)
|
|
170
|
+
options.default_layout = nil
|
|
171
|
+
options.paths = default_preview_paths
|
|
203
172
|
options
|
|
204
173
|
end
|
|
205
174
|
end
|
|
206
175
|
|
|
207
176
|
# @!attribute current
|
|
177
|
+
#
|
|
208
178
|
# @return [ViewComponent::Config]
|
|
209
179
|
# Returns the current ViewComponent::Config. This is persisted against this
|
|
210
180
|
# class so that config options remain accessible before the rest of
|
|
@@ -4,14 +4,30 @@ module ViewComponent
|
|
|
4
4
|
module Configurable
|
|
5
5
|
extend ActiveSupport::Concern
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
class_methods do
|
|
8
|
+
def config
|
|
9
|
+
@_config ||= if respond_to?(:superclass) && superclass.respond_to?(:config)
|
|
10
|
+
superclass.config.inheritable_copy
|
|
11
|
+
else
|
|
12
|
+
ActiveSupport::OrderedOptions.new
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def configure
|
|
17
|
+
yield config
|
|
18
|
+
end
|
|
19
|
+
end
|
|
9
20
|
|
|
10
|
-
|
|
21
|
+
included do
|
|
22
|
+
next if respond_to?(:config) && config.respond_to?(:view_component) && config.respond_to_missing?(:instrumentation_enabled)
|
|
11
23
|
|
|
12
24
|
configure do |config|
|
|
13
25
|
config.view_component ||= ActiveSupport::InheritableOptions.new
|
|
14
26
|
end
|
|
27
|
+
|
|
28
|
+
def config
|
|
29
|
+
self.class.config
|
|
30
|
+
end
|
|
15
31
|
end
|
|
16
32
|
end
|
|
17
33
|
end
|