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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6bb3c2781d5f07f404e5bf9582758537704a05c3937529c250ae657541d4f664
4
- data.tar.gz: 0efa6d2e3bbf03ed206e02b9dad11bea1f5649ab655dfff78d1f48c68414129f
3
+ metadata.gz: 8ec532b985935e7b718bb74aa51eaaa5e5f26ea0df8936e0c131231c9e9c37ed
4
+ data.tar.gz: c0cde4fa2a1b4d2c0110085b8c3c1b4705117f9ffe20775a096c5c3b20aa0728
5
5
  SHA512:
6
- metadata.gz: 9222381535158cc047e33e37341329c232ac984ee3f6895e95251cd9dabc9b92baebb69b336500932c264b48eb7f74ef0b7d3f918473d8fe83151ad73c18323b
7
- data.tar.gz: 4da1bd8980affd316288695a52e9fcdccad912f3447081f0186194190ad48e52d397f36c34b3bea70ea743d32f2eda8d37779ecb588b50cbd626f7d89a4f365c
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 %>
@@ -7,6 +7,8 @@ module ViewComponent
7
7
 
8
8
  autoload :Base
9
9
  autoload :Compiler
10
+ autoload :ComponentError
11
+ autoload :Instrumentation
10
12
  autoload :Preview
11
13
  autoload :PreviewTemplateError
12
14
  autoload :TestHelpers
@@ -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
- # Provides a proxy to access helper methods from the context of the current controller
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
- private
173
-
174
- # Exposes the current request to the component.
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
- template_compiler.compiled?
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
- template_compiler.compile(raise_errors: raise_errors)
335
+ compiler.compile(raise_errors: raise_errors)
292
336
  end
293
337
 
294
- def template_compiler
295
- @_template_compiler ||= Compiler.new(self)
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 ArgumentError.new(
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
- instance_method(:initialize).parameters.map(&:second).include?(collection_counter_parameter)
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 component_class.instance_methods(false).include?(:before_render_check)
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
  )
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ class ComponentError < StandardError
5
+ end
6
+ end
@@ -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
- # render_in is faster than `parent.render`
31
- if defined?(@_content_block)
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
- # <%= component.header(classes: "Foo") do %>
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
- # <%= items.each do |item| %>
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
- # <%= component.item(name: "Foo") do %>
110
+ # <% component.item(name: "Foo") do %>
111
111
  # <p>One</p>
112
112
  # <% end %>
113
113
  #
114
- # <%= component.item(name: "Bar") do %>
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
- nil
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 ||= ActionDispatch::TestRequest.create
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
- unless CompileCache.compiled? self
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: _sidecar_files(%w[yml yaml]),
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, locale: nil, **options)
59
- locale ||= ::I18n.locale
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
- result = catch(:exception) do
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 result.is_a? ::I18n::MissingTranslation
69
- result = helpers.t(key, locale: locale, **options)
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
- result
86
+ translated
73
87
  end
74
88
  alias :t :translate
75
89
 
@@ -3,7 +3,7 @@
3
3
  module ViewComponent
4
4
  module VERSION
5
5
  MAJOR = 2
6
- MINOR = 30
6
+ MINOR = 34
7
7
  PATCH = 0
8
8
 
9
9
  STRING = [MAJOR, MINOR, PATCH].join(".")
@@ -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.30.0
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-04-02 00:00:00.000000000 Z
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
- description:
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.1.2
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: []