view_component 2.30.0 → 2.34.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/CHANGELOG.md +88 -0
- data/app/views/test_mailer/test_email.html.erb +1 -0
- data/lib/view_component.rb +2 -0
- data/lib/view_component/base.rb +66 -14
- data/lib/view_component/collection.rb +1 -0
- data/lib/view_component/compiler.rb +7 -1
- data/lib/view_component/component_error.rb +6 -0
- data/lib/view_component/engine.rb +13 -2
- data/lib/view_component/instrumentation.rb +17 -0
- data/lib/view_component/slot_v2.rb +16 -2
- data/lib/view_component/slotable.rb +5 -0
- data/lib/view_component/slotable_v2.rb +9 -5
- data/lib/view_component/test_helpers.rb +17 -1
- data/lib/view_component/translatable.rb +22 -8
- data/lib/view_component/version.rb +1 -1
- data/lib/view_component/with_content_helper.rb +15 -0
- metadata +25 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8ec532b985935e7b718bb74aa51eaaa5e5f26ea0df8936e0c131231c9e9c37ed
|
4
|
+
data.tar.gz: c0cde4fa2a1b4d2c0110085b8c3c1b4705117f9ffe20775a096c5c3b20aa0728
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 37cfdfd8cbf06773a015c13ed6f8c079f9d269045ba8ab1981e56d90cccf841152a8c9ab018b66c5289b8a1bbe5e4c7d1c8a0645e70578b1e97d9da098fe95cd
|
7
|
+
data.tar.gz: fe210839c3be3a8eb83e2bac1655f3ab5c5dc8d49727a413ba5ac46eeb0b4bb41e32f18c67b295bfe927cfc207dcc9df7f0c71f6ebc7f6064ea1c7c9fef6ddb7
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,94 @@
|
|
2
2
|
|
3
3
|
## main
|
4
4
|
|
5
|
+
## 2.34.0
|
6
|
+
|
7
|
+
* Add the ability to enable ActiveSupport notifications (`!render.view_component` event) with `config.view_component.instrumentation_enabled`.
|
8
|
+
|
9
|
+
*Svyatoslav Kryukov*
|
10
|
+
|
11
|
+
* Add [Generators](https://viewcomponent.org/guide/generators.html) page to documentation.
|
12
|
+
|
13
|
+
*Hans Lemuet*
|
14
|
+
|
15
|
+
* Fix bug where ViewComponents did not work in ActionMailers.
|
16
|
+
|
17
|
+
*dark-panda*
|
18
|
+
|
19
|
+
## 2.33.0
|
20
|
+
|
21
|
+
* Add support for `_iteration` parameter when rendering in a collection
|
22
|
+
|
23
|
+
*Will Cosgrove*
|
24
|
+
|
25
|
+
* Don't raise an error when rendering empty components.
|
26
|
+
|
27
|
+
*Alex Robbin*
|
28
|
+
|
29
|
+
## 2.32.0
|
30
|
+
|
31
|
+
* Enable previews by default in test environment.
|
32
|
+
|
33
|
+
*Edouard Piron*
|
34
|
+
|
35
|
+
* Fix test helper compatibility with Rails 7.0, TestRequest, and TestSession.
|
36
|
+
|
37
|
+
*Leo Correa*
|
38
|
+
|
39
|
+
* Add experimental `_output_postamble` lifecyle method.
|
40
|
+
|
41
|
+
*Joel Hawksley*
|
42
|
+
|
43
|
+
* Add compatibility notes on FAQ.
|
44
|
+
|
45
|
+
*Matheus Richard*
|
46
|
+
|
47
|
+
* Add Bridgetown on Compatibility documentation.
|
48
|
+
|
49
|
+
*Matheus Richard*
|
50
|
+
|
51
|
+
* Are you interested in building the future of ViewComponent? GitHub is looking to hire a Senior Engineer to work on Primer ViewComponents and ViewComponent. Apply here: [US/Canada](https://github.com/careers) / [Europe](https://boards.greenhouse.io/github/jobs/3132294). Feel free to reach out to joelhawksley@github.com with any questions.
|
52
|
+
|
53
|
+
*Joel Hawksley*
|
54
|
+
|
55
|
+
## 2.31.1
|
56
|
+
|
57
|
+
* Fix `DEPRECATION WARNING: before_render_check` when compiling `ViewComponent::Base`
|
58
|
+
|
59
|
+
*Dave Kroondyk*
|
60
|
+
|
61
|
+
## 2.31.0
|
62
|
+
|
63
|
+
_Note: This release includes an underlying change to Slots that may affect incorrect usage of the API, where Slots were set on a line prefixed by `<%=`. The result of setting a Slot should not be returned. (`<%`)_
|
64
|
+
|
65
|
+
* Add `#with_content` to allow setting content without a block.
|
66
|
+
|
67
|
+
*Jordan Raine, Manuel Puyol*
|
68
|
+
|
69
|
+
* Add `with_request_url` test helper.
|
70
|
+
|
71
|
+
*Mario Schüttel*
|
72
|
+
|
73
|
+
* Improve feature parity with Rails translations
|
74
|
+
* Don't create a translation backend if the component has no translation file
|
75
|
+
* Mark translation keys ending with `html` as HTML-safe
|
76
|
+
* Always convert keys to String
|
77
|
+
* Support multiple keys
|
78
|
+
|
79
|
+
*Elia Schito*
|
80
|
+
|
81
|
+
* Fix errors on `asset_url` helpers when `asset_host` has no protocol.
|
82
|
+
|
83
|
+
*Elia Schito*
|
84
|
+
|
85
|
+
* Prevent slots from overriding the `#content` method when registering a slot with that name.
|
86
|
+
|
87
|
+
*Blake Williams*
|
88
|
+
|
89
|
+
* Deprecate `with_slot` in favor of the new [slots API](https://viewcomponent.org/guide/slots.html).
|
90
|
+
|
91
|
+
*Manuel Puyol*
|
92
|
+
|
5
93
|
## 2.30.0
|
6
94
|
|
7
95
|
* Deprecate `with_content_areas` in favor of [slots](https://viewcomponent.org/guide/slots.html).
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= render MailerComponent.new %>
|
data/lib/view_component.rb
CHANGED
data/lib/view_component/base.rb
CHANGED
@@ -7,12 +7,14 @@ require "view_component/compile_cache"
|
|
7
7
|
require "view_component/previewable"
|
8
8
|
require "view_component/slotable"
|
9
9
|
require "view_component/slotable_v2"
|
10
|
+
require "view_component/with_content_helper"
|
10
11
|
|
11
12
|
module ViewComponent
|
12
13
|
class Base < ActionView::Base
|
13
14
|
include ActiveSupport::Configurable
|
14
15
|
include ViewComponent::Previewable
|
15
16
|
include ViewComponent::SlotableV2
|
17
|
+
include ViewComponent::WithContentHelper
|
16
18
|
|
17
19
|
ViewContextCalledBeforeRenderError = Class.new(StandardError)
|
18
20
|
|
@@ -28,6 +30,7 @@ module ViewComponent
|
|
28
30
|
# Hook for allowing components to do work as part of the compilation process.
|
29
31
|
#
|
30
32
|
# For example, one might compile component-specific assets at this point.
|
33
|
+
# @private TODO: add documentation
|
31
34
|
def self._after_compile
|
32
35
|
# noop
|
33
36
|
end
|
@@ -56,6 +59,7 @@ module ViewComponent
|
|
56
59
|
# returns:
|
57
60
|
# <span title="greeting">Hello, world!</span>
|
58
61
|
#
|
62
|
+
# @private
|
59
63
|
def render_in(view_context, &block)
|
60
64
|
self.class.compile(raise_errors: true)
|
61
65
|
|
@@ -79,13 +83,15 @@ module ViewComponent
|
|
79
83
|
old_current_template = @current_template
|
80
84
|
@current_template = self
|
81
85
|
|
86
|
+
raise ArgumentError.new("Block provided after calling `with_content`. Use one or the other.") if block && defined?(@_content_set_by_with_content)
|
87
|
+
|
82
88
|
@_content_evaluated = false
|
83
89
|
@_render_in_block = block
|
84
90
|
|
85
91
|
before_render
|
86
92
|
|
87
93
|
if render?
|
88
|
-
render_template_for(@variant)
|
94
|
+
render_template_for(@variant).to_s + _output_postamble
|
89
95
|
else
|
90
96
|
""
|
91
97
|
end
|
@@ -93,18 +99,36 @@ module ViewComponent
|
|
93
99
|
@current_template = old_current_template
|
94
100
|
end
|
95
101
|
|
102
|
+
# EXPERIMENTAL: Optional content to be returned after the rendered template.
|
103
|
+
#
|
104
|
+
# @return [String]
|
105
|
+
def _output_postamble
|
106
|
+
""
|
107
|
+
end
|
108
|
+
|
109
|
+
# Called before rendering the component. Override to perform operations that depend on having access to the view context, such as helpers.
|
110
|
+
#
|
111
|
+
# @return [void]
|
96
112
|
def before_render
|
97
113
|
before_render_check
|
98
114
|
end
|
99
115
|
|
116
|
+
# Called after rendering the component.
|
117
|
+
#
|
118
|
+
# @deprecated Use `before_render` instead. Will be removed in v3.0.0.
|
119
|
+
# @return [void]
|
100
120
|
def before_render_check
|
101
121
|
# noop
|
102
122
|
end
|
103
123
|
|
124
|
+
# Override to determine whether the ViewComponent should render.
|
125
|
+
#
|
126
|
+
# @return [Boolean]
|
104
127
|
def render?
|
105
128
|
true
|
106
129
|
end
|
107
130
|
|
131
|
+
# @private
|
108
132
|
def initialize(*); end
|
109
133
|
|
110
134
|
# Re-use original view_context if we're not rendering a component.
|
@@ -112,6 +136,8 @@ module ViewComponent
|
|
112
136
|
# This prevents an exception when rendering a partial inside of a component that has also been rendered outside
|
113
137
|
# of the component. This is due to the partials compiled template method existing in the parent `view_context`,
|
114
138
|
# and not the component's `view_context`.
|
139
|
+
#
|
140
|
+
# @private
|
115
141
|
def render(options = {}, args = {}, &block)
|
116
142
|
if options.is_a? ViewComponent::Base
|
117
143
|
super
|
@@ -120,28 +146,38 @@ module ViewComponent
|
|
120
146
|
end
|
121
147
|
end
|
122
148
|
|
149
|
+
# The current controller. Use sparingly as doing so introduces coupling that inhibits encapsulation & reuse, often making testing difficult.
|
150
|
+
#
|
151
|
+
# @return [ActionController::Base]
|
123
152
|
def controller
|
124
153
|
raise ViewContextCalledBeforeRenderError, "`controller` can only be called at render time." if view_context.nil?
|
125
154
|
@controller ||= view_context.controller
|
126
155
|
end
|
127
156
|
|
128
|
-
#
|
157
|
+
# A proxy through which to access helpers. Use sparingly as doing so introduces coupling that inhibits encapsulation & reuse, often making testing difficult.
|
158
|
+
#
|
159
|
+
# @return [ActionView::Base]
|
129
160
|
def helpers
|
130
161
|
raise ViewContextCalledBeforeRenderError, "`helpers` can only be called at render time." if view_context.nil?
|
131
162
|
@helpers ||= controller.view_context
|
132
163
|
end
|
133
164
|
|
134
165
|
# Exposes .virtual_path as an instance method
|
166
|
+
#
|
167
|
+
# @private
|
135
168
|
def virtual_path
|
136
169
|
self.class.virtual_path
|
137
170
|
end
|
138
171
|
|
139
172
|
# For caching, such as #cache_if
|
173
|
+
# @private
|
140
174
|
def view_cache_dependencies
|
141
175
|
[]
|
142
176
|
end
|
143
177
|
|
144
178
|
# For caching, such as #cache_if
|
179
|
+
#
|
180
|
+
# @private
|
145
181
|
def format
|
146
182
|
# Ruby 2.6 throws a warning without checking `defined?`, 2.7 does not
|
147
183
|
if defined?(@variant)
|
@@ -150,6 +186,8 @@ module ViewComponent
|
|
150
186
|
end
|
151
187
|
|
152
188
|
# Assign the provided content to the content area accessor
|
189
|
+
#
|
190
|
+
# @private
|
153
191
|
def with(area, content = nil, &block)
|
154
192
|
unless content_areas.include?(area)
|
155
193
|
raise ArgumentError.new "Unknown content_area '#{area}' - expected one of '#{content_areas}'"
|
@@ -163,21 +201,25 @@ module ViewComponent
|
|
163
201
|
nil
|
164
202
|
end
|
165
203
|
|
204
|
+
# Use the provided variant instead of the one determined by the current request.
|
205
|
+
#
|
206
|
+
# @param variant [Symbol] The variant to be used by the component.
|
207
|
+
# @return [self]
|
166
208
|
def with_variant(variant)
|
167
209
|
@variant = variant
|
168
210
|
|
169
211
|
self
|
170
212
|
end
|
171
213
|
|
172
|
-
|
173
|
-
|
174
|
-
#
|
175
|
-
# Use sparingly as doing so introduces coupling
|
176
|
-
# that inhibits encapsulation & reuse.
|
214
|
+
# The current request. Use sparingly as doing so introduces coupling that inhibits encapsulation & reuse, often making testing difficult.
|
215
|
+
#
|
216
|
+
# @return [ActionDispatch::Request]
|
177
217
|
def request
|
178
|
-
@request ||= controller.request
|
218
|
+
@request ||= controller.request if controller.respond_to?(:request)
|
179
219
|
end
|
180
220
|
|
221
|
+
private
|
222
|
+
|
181
223
|
attr_reader :view_context
|
182
224
|
|
183
225
|
def content
|
@@ -186,6 +228,8 @@ module ViewComponent
|
|
186
228
|
|
187
229
|
@_content = if @view_context && @_render_in_block
|
188
230
|
view_context.capture(self, &@_render_in_block)
|
231
|
+
elsif defined?(@_content_set_by_with_content)
|
232
|
+
@_content_set_by_with_content
|
189
233
|
end
|
190
234
|
end
|
191
235
|
|
@@ -280,7 +324,7 @@ module ViewComponent
|
|
280
324
|
end
|
281
325
|
|
282
326
|
def compiled?
|
283
|
-
|
327
|
+
compiler.compiled?
|
284
328
|
end
|
285
329
|
|
286
330
|
# Compile templates to instance methods, assuming they haven't been compiled already.
|
@@ -288,11 +332,11 @@ module ViewComponent
|
|
288
332
|
# Do as much work as possible in this step, as doing so reduces the amount
|
289
333
|
# of work done each time a component is rendered.
|
290
334
|
def compile(raise_errors: false)
|
291
|
-
|
335
|
+
compiler.compile(raise_errors: raise_errors)
|
292
336
|
end
|
293
337
|
|
294
|
-
def
|
295
|
-
@
|
338
|
+
def compiler
|
339
|
+
@_compiler ||= Compiler.new(self)
|
296
340
|
end
|
297
341
|
|
298
342
|
# we'll eventually want to update this to support other types
|
@@ -365,7 +409,7 @@ module ViewComponent
|
|
365
409
|
def validate_initialization_parameters!
|
366
410
|
return unless initialize_parameter_names.include?(RESERVED_PARAMETER)
|
367
411
|
|
368
|
-
raise
|
412
|
+
raise ViewComponent::ComponentError.new(
|
369
413
|
"#{self} initializer cannot contain " \
|
370
414
|
"`#{RESERVED_PARAMETER}` since it will override a " \
|
371
415
|
"public ViewComponent method."
|
@@ -385,7 +429,15 @@ module ViewComponent
|
|
385
429
|
end
|
386
430
|
|
387
431
|
def counter_argument_present?
|
388
|
-
|
432
|
+
initialize_parameter_names.include?(collection_counter_parameter)
|
433
|
+
end
|
434
|
+
|
435
|
+
def collection_iteration_parameter
|
436
|
+
"#{collection_parameter}_iteration".to_sym
|
437
|
+
end
|
438
|
+
|
439
|
+
def iteration_argument_present?
|
440
|
+
initialize_parameter_names.include?(collection_iteration_parameter)
|
389
441
|
end
|
390
442
|
|
391
443
|
private
|
@@ -38,6 +38,7 @@ module ViewComponent
|
|
38
38
|
def component_options(item, iterator)
|
39
39
|
item_options = { component.collection_parameter => item }
|
40
40
|
item_options[component.collection_counter_parameter] = iterator.index + 1 if component.counter_argument_present?
|
41
|
+
item_options[component.collection_iteration_parameter] = iterator if component.iteration_argument_present?
|
41
42
|
|
42
43
|
@options.merge(item_options)
|
43
44
|
end
|
@@ -13,12 +13,18 @@ module ViewComponent
|
|
13
13
|
def compile(raise_errors: false)
|
14
14
|
return if compiled?
|
15
15
|
|
16
|
+
subclass_instance_methods = component_class.instance_methods(false)
|
17
|
+
|
18
|
+
if subclass_instance_methods.include?(:with_content) && raise_errors
|
19
|
+
raise ViewComponent::ComponentError.new("#{component_class} implements a reserved method, `with_content`.")
|
20
|
+
end
|
21
|
+
|
16
22
|
if template_errors.present?
|
17
23
|
raise ViewComponent::TemplateError.new(template_errors) if raise_errors
|
18
24
|
return false
|
19
25
|
end
|
20
26
|
|
21
|
-
if
|
27
|
+
if subclass_instance_methods.include?(:before_render_check)
|
22
28
|
ActiveSupport::Deprecation.warn(
|
23
29
|
"`before_render_check` will be removed in v3.0.0. Use `before_render` instead."
|
24
30
|
)
|
@@ -12,7 +12,8 @@ module ViewComponent
|
|
12
12
|
options = app.config.view_component
|
13
13
|
|
14
14
|
options.render_monkey_patch_enabled = true if options.render_monkey_patch_enabled.nil?
|
15
|
-
options.show_previews = Rails.env.development? if options.show_previews.nil?
|
15
|
+
options.show_previews = Rails.env.development? || Rails.env.test? if options.show_previews.nil?
|
16
|
+
options.instrumentation_enabled = false if options.instrumentation_enabled.nil?
|
16
17
|
options.preview_route ||= ViewComponent::Base.preview_route
|
17
18
|
options.preview_controller ||= ViewComponent::Base.preview_controller
|
18
19
|
|
@@ -30,7 +31,17 @@ module ViewComponent
|
|
30
31
|
end
|
31
32
|
|
32
33
|
ActiveSupport.on_load(:view_component) do
|
33
|
-
options.each { |k, v| send("#{k}=", v) }
|
34
|
+
options.each { |k, v| send("#{k}=", v) if respond_to?("#{k}=") }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
initializer "view_component.enable_instrumentation" do |app|
|
39
|
+
ActiveSupport.on_load(:view_component) do
|
40
|
+
if app.config.view_component.instrumentation_enabled.present?
|
41
|
+
# :nocov:
|
42
|
+
ViewComponent::Base.prepend(ViewComponent::Instrumentation)
|
43
|
+
# :nocov:
|
44
|
+
end
|
34
45
|
end
|
35
46
|
end
|
36
47
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/notifications"
|
4
|
+
|
5
|
+
module ViewComponent # :nodoc:
|
6
|
+
module Instrumentation
|
7
|
+
def self.included(mod)
|
8
|
+
mod.prepend(self)
|
9
|
+
end
|
10
|
+
|
11
|
+
def render_in(view_context, &block)
|
12
|
+
ActiveSupport::Notifications.instrument("!render.view_component", name: self.class.name, identifier: self.class.identifier) do
|
13
|
+
super(view_context, &block)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -1,7 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "view_component/with_content_helper"
|
4
|
+
|
3
5
|
module ViewComponent
|
4
6
|
class SlotV2
|
7
|
+
include ViewComponent::WithContentHelper
|
8
|
+
|
5
9
|
attr_writer :_component_instance, :_content_block, :_content
|
6
10
|
|
7
11
|
def initialize(parent)
|
@@ -26,10 +30,18 @@ module ViewComponent
|
|
26
30
|
|
27
31
|
view_context = @parent.send(:view_context)
|
28
32
|
|
33
|
+
raise ArgumentError.new("Block provided after calling `with_content`. Use one or the other.") if defined?(@_content_block) && defined?(@_content_set_by_with_content)
|
34
|
+
|
29
35
|
@content = if defined?(@_component_instance)
|
30
|
-
|
31
|
-
|
36
|
+
if defined?(@_content_set_by_with_content)
|
37
|
+
@_component_instance.with_content(@_content_set_by_with_content)
|
38
|
+
|
39
|
+
view_context.capture do
|
40
|
+
@_component_instance.render_in(view_context)
|
41
|
+
end
|
42
|
+
elsif defined?(@_content_block)
|
32
43
|
view_context.capture do
|
44
|
+
# render_in is faster than `parent.render`
|
33
45
|
@_component_instance.render_in(view_context, &@_content_block)
|
34
46
|
end
|
35
47
|
else
|
@@ -41,6 +53,8 @@ module ViewComponent
|
|
41
53
|
@_content
|
42
54
|
elsif defined?(@_content_block)
|
43
55
|
view_context.capture(&@_content_block)
|
56
|
+
elsif defined?(@_content_set_by_with_content)
|
57
|
+
@_content_set_by_with_content
|
44
58
|
end
|
45
59
|
|
46
60
|
@content
|
@@ -23,6 +23,11 @@ module ViewComponent
|
|
23
23
|
# class_name: "Header" # class name string, used to instantiate Slot
|
24
24
|
# )
|
25
25
|
def with_slot(*slot_names, collection: false, class_name: nil)
|
26
|
+
ActiveSupport::Deprecation.warn(
|
27
|
+
"`with_slot` is deprecated and will be removed in ViewComponent v3.0.0.\n" \
|
28
|
+
"Use the new slots API (https://viewcomponent.org/guide/slots.html) instead."
|
29
|
+
)
|
30
|
+
|
26
31
|
slot_names.each do |slot_name|
|
27
32
|
# Ensure slot_name is not already declared
|
28
33
|
if self.slots.key?(slot_name)
|
@@ -60,7 +60,7 @@ module ViewComponent
|
|
60
60
|
# helper method with the same name as the slot.
|
61
61
|
#
|
62
62
|
# <%= render_inline(MyComponent.new) do |component| %>
|
63
|
-
#
|
63
|
+
# <% component.header(classes: "Foo") do %>
|
64
64
|
# <p>Bar</p>
|
65
65
|
# <% end %>
|
66
66
|
# <% end %>
|
@@ -95,7 +95,7 @@ module ViewComponent
|
|
95
95
|
# helper method with the same name as the slot.
|
96
96
|
#
|
97
97
|
# <h1>
|
98
|
-
#
|
98
|
+
# <% items.each do |item| %>
|
99
99
|
# <%= item %>
|
100
100
|
# <% end %>
|
101
101
|
# </h1>
|
@@ -107,11 +107,11 @@ module ViewComponent
|
|
107
107
|
# called multiple times to append to the slot.
|
108
108
|
#
|
109
109
|
# <%= render_inline(MyComponent.new) do |component| %>
|
110
|
-
#
|
110
|
+
# <% component.item(name: "Foo") do %>
|
111
111
|
# <p>One</p>
|
112
112
|
# <% end %>
|
113
113
|
#
|
114
|
-
#
|
114
|
+
# <% component.item(name: "Bar") do %>
|
115
115
|
# <p>two</p>
|
116
116
|
# <% end %>
|
117
117
|
# <% end %>
|
@@ -175,6 +175,10 @@ module ViewComponent
|
|
175
175
|
end
|
176
176
|
|
177
177
|
def validate_slot_name(slot_name)
|
178
|
+
if slot_name.to_sym == :content
|
179
|
+
raise ArgumentError.new("#{slot_name} is not a valid slot name.")
|
180
|
+
end
|
181
|
+
|
178
182
|
if self.registered_slots.key?(slot_name)
|
179
183
|
# TODO remove? This breaks overriding slots when slots are inherited
|
180
184
|
raise ArgumentError.new("#{slot_name} slot declared multiple times")
|
@@ -251,7 +255,7 @@ module ViewComponent
|
|
251
255
|
@_set_slots[slot_name] = slot
|
252
256
|
end
|
253
257
|
|
254
|
-
|
258
|
+
slot
|
255
259
|
end
|
256
260
|
end
|
257
261
|
end
|
@@ -39,7 +39,12 @@ module ViewComponent
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def request
|
42
|
-
@request ||=
|
42
|
+
@request ||=
|
43
|
+
begin
|
44
|
+
request = ActionDispatch::TestRequest.create
|
45
|
+
request.session = ActionController::TestSession.new
|
46
|
+
request
|
47
|
+
end
|
43
48
|
end
|
44
49
|
|
45
50
|
def with_variant(variant)
|
@@ -60,6 +65,17 @@ module ViewComponent
|
|
60
65
|
@controller = old_controller
|
61
66
|
end
|
62
67
|
|
68
|
+
def with_request_url(path)
|
69
|
+
old_request_path_parameters = request.path_parameters
|
70
|
+
old_controller = defined?(@controller) && @controller
|
71
|
+
|
72
|
+
request.path_parameters = Rails.application.routes.recognize_path(path)
|
73
|
+
yield
|
74
|
+
ensure
|
75
|
+
request.path_parameters = old_request_path_parameters
|
76
|
+
@controller = old_controller
|
77
|
+
end
|
78
|
+
|
63
79
|
def build_controller(klass)
|
64
80
|
klass.new.tap { |c| c.request = request }.extend(Rails.application.routes.url_helpers)
|
65
81
|
end
|
@@ -9,6 +9,8 @@ module ViewComponent
|
|
9
9
|
module Translatable
|
10
10
|
extend ActiveSupport::Concern
|
11
11
|
|
12
|
+
HTML_SAFE_TRANSLATION_KEY = /(?:_|\b)html\z/.freeze
|
13
|
+
|
12
14
|
included do
|
13
15
|
class_attribute :i18n_backend, instance_writer: false, instance_predicate: false
|
14
16
|
end
|
@@ -21,11 +23,16 @@ module ViewComponent
|
|
21
23
|
def _after_compile
|
22
24
|
super
|
23
25
|
|
24
|
-
|
26
|
+
return if CompileCache.compiled? self
|
27
|
+
|
28
|
+
if (translation_files = _sidecar_files(%w[yml yaml])).any?
|
25
29
|
self.i18n_backend = I18nBackend.new(
|
26
30
|
i18n_scope: i18n_scope,
|
27
|
-
load_paths:
|
31
|
+
load_paths: translation_files,
|
28
32
|
)
|
33
|
+
else
|
34
|
+
# Cleanup if translations file has been removed since the last compilation
|
35
|
+
self.i18n_backend = nil
|
29
36
|
end
|
30
37
|
end
|
31
38
|
end
|
@@ -55,21 +62,28 @@ module ViewComponent
|
|
55
62
|
end
|
56
63
|
end
|
57
64
|
|
58
|
-
def translate(key = nil,
|
59
|
-
|
65
|
+
def translate(key = nil, **options)
|
66
|
+
return super unless i18n_backend
|
67
|
+
return key.map { |k| translate(k, **options) } if key.is_a?(Array)
|
60
68
|
|
69
|
+
locale = options.delete(:locale) || ::I18n.locale
|
70
|
+
key = key&.to_s unless key.is_a?(String)
|
61
71
|
key = "#{i18n_scope}#{key}" if key.start_with?(".")
|
62
72
|
|
63
|
-
|
73
|
+
translated = catch(:exception) do
|
64
74
|
i18n_backend.translate(locale, key, options)
|
65
75
|
end
|
66
76
|
|
67
77
|
# Fallback to the global translations
|
68
|
-
if
|
69
|
-
|
78
|
+
if translated.is_a? ::I18n::MissingTranslation
|
79
|
+
return super(key, locale: locale, **options)
|
80
|
+
end
|
81
|
+
|
82
|
+
if HTML_SAFE_TRANSLATION_KEY.match?(key)
|
83
|
+
translated = translated.html_safe
|
70
84
|
end
|
71
85
|
|
72
|
-
|
86
|
+
translated
|
73
87
|
end
|
74
88
|
alias :t :translate
|
75
89
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
module WithContentHelper
|
5
|
+
def with_content(value)
|
6
|
+
if value.nil?
|
7
|
+
raise ArgumentError.new("No content provided.")
|
8
|
+
else
|
9
|
+
@_content_set_by_with_content = value
|
10
|
+
end
|
11
|
+
|
12
|
+
self
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: view_component
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.34.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GitHub Open Source
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-06-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -212,7 +212,21 @@ dependencies:
|
|
212
212
|
- - "~>"
|
213
213
|
- !ruby/object:Gem::Version
|
214
214
|
version: '0.13'
|
215
|
-
|
215
|
+
- !ruby/object:Gem::Dependency
|
216
|
+
name: yard
|
217
|
+
requirement: !ruby/object:Gem::Requirement
|
218
|
+
requirements:
|
219
|
+
- - "~>"
|
220
|
+
- !ruby/object:Gem::Version
|
221
|
+
version: 0.9.25
|
222
|
+
type: :development
|
223
|
+
prerelease: false
|
224
|
+
version_requirements: !ruby/object:Gem::Requirement
|
225
|
+
requirements:
|
226
|
+
- - "~>"
|
227
|
+
- !ruby/object:Gem::Version
|
228
|
+
version: 0.9.25
|
229
|
+
description:
|
216
230
|
email:
|
217
231
|
- opensource+view_component@github.com
|
218
232
|
executables: []
|
@@ -223,6 +237,7 @@ files:
|
|
223
237
|
- LICENSE.txt
|
224
238
|
- README.md
|
225
239
|
- app/controllers/view_components_controller.rb
|
240
|
+
- app/views/test_mailer/test_email.html.erb
|
226
241
|
- app/views/view_components/index.html.erb
|
227
242
|
- app/views/view_components/preview.html.erb
|
228
243
|
- app/views/view_components/previews.html.erb
|
@@ -246,7 +261,9 @@ files:
|
|
246
261
|
- lib/view_component/collection.rb
|
247
262
|
- lib/view_component/compile_cache.rb
|
248
263
|
- lib/view_component/compiler.rb
|
264
|
+
- lib/view_component/component_error.rb
|
249
265
|
- lib/view_component/engine.rb
|
266
|
+
- lib/view_component/instrumentation.rb
|
250
267
|
- lib/view_component/preview.rb
|
251
268
|
- lib/view_component/preview_template_error.rb
|
252
269
|
- lib/view_component/previewable.rb
|
@@ -265,12 +282,13 @@ files:
|
|
265
282
|
- lib/view_component/test_helpers.rb
|
266
283
|
- lib/view_component/translatable.rb
|
267
284
|
- lib/view_component/version.rb
|
285
|
+
- lib/view_component/with_content_helper.rb
|
268
286
|
homepage: https://github.com/github/view_component
|
269
287
|
licenses:
|
270
288
|
- MIT
|
271
289
|
metadata:
|
272
290
|
allowed_push_host: https://rubygems.org
|
273
|
-
post_install_message:
|
291
|
+
post_install_message:
|
274
292
|
rdoc_options: []
|
275
293
|
require_paths:
|
276
294
|
- lib
|
@@ -285,8 +303,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
285
303
|
- !ruby/object:Gem::Version
|
286
304
|
version: '0'
|
287
305
|
requirements: []
|
288
|
-
rubygems_version: 3.
|
289
|
-
signing_key:
|
306
|
+
rubygems_version: 3.2.3
|
307
|
+
signing_key:
|
290
308
|
specification_version: 4
|
291
309
|
summary: View components for Rails
|
292
310
|
test_files: []
|