view_component 2.11.0 → 2.14.1
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 +45 -0
- data/README.md +153 -8
- data/lib/view_component/base.rb +14 -2
- data/lib/view_component/collection.rb +1 -1
- data/lib/view_component/engine.rb +35 -12
- data/lib/view_component/preview.rb +3 -3
- data/lib/view_component/previewable.rb +4 -1
- data/lib/view_component/render_component_helper.rb +9 -0
- data/lib/view_component/render_component_to_string_helper.rb +9 -0
- data/lib/view_component/rendering_component_helper.rb +9 -0
- data/lib/view_component/slot.rb +7 -0
- data/lib/view_component/slotable.rb +121 -0
- data/lib/view_component/test_helpers.rb +7 -2
- data/lib/view_component/version.rb +2 -2
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '084152c558b71f87f41d620f9cdce42e689e0b4159cdfa68f3cb041a7bbea3ba'
|
4
|
+
data.tar.gz: 45324159a07873ce92562650fe7c2ad6e8a279c3db216b3460a6075f71033180
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 58f994aac7efdf81146972a351a12726131658e4ccbd8bf0661eb135d7935ff396c64752d9f9edd6dda50b90a4829aeb506f24edee712279aa1cf4bf4f15886d
|
7
|
+
data.tar.gz: 430b55482aaafaea6a27e73593861f897620cb635c2a2f14f14b5a772846a8f5a7b42bd973f637cd587816762891bcc432ced92dbac04fe1d391bf7734873a6a
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,50 @@
|
|
1
1
|
# master
|
2
2
|
|
3
|
+
# 2.14.1
|
4
|
+
|
5
|
+
* Allow using `render_inline` in test when the render monkey patch is disabled with `config.view_component.render_monkey_patch_enabled = false` in versions of Rails < 6.1.
|
6
|
+
|
7
|
+
*Clément Joubert*
|
8
|
+
|
9
|
+
* Fix kwargs warnings in slotable.
|
10
|
+
|
11
|
+
Fixes:
|
12
|
+
|
13
|
+
```
|
14
|
+
view_component/lib/view_component/slotable.rb:98: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
|
15
|
+
view_component/test/app/components/slots_component.rb:18: warning: The called method `initialize' is defined here
|
16
|
+
```
|
17
|
+
|
18
|
+
*Eileen M. Uchitelle*
|
19
|
+
|
20
|
+
# 2.14.0
|
21
|
+
|
22
|
+
* Add `config.preview_paths` to support multiple locations of component preview files. Deprecate `config.preview_path`.
|
23
|
+
|
24
|
+
*Tomas Celizna*
|
25
|
+
|
26
|
+
* Only print warning about a missing capybara dependency if the `DEBUG` environment variable is set.
|
27
|
+
|
28
|
+
*Richard Macklin*
|
29
|
+
|
30
|
+
# 2.13.0
|
31
|
+
|
32
|
+
* Add the ability to disable the render monkey patch with `config.view_component.render_monkey_patch_enabled`. In versions of Rails < 6.1, add `render_component` and `render_component_to_string` methods which can be used for rendering components instead of `render`.
|
33
|
+
|
34
|
+
*Johannes Engl*
|
35
|
+
|
36
|
+
# 2.12.0
|
37
|
+
|
38
|
+
* Implement Slots as potential successor to Content Areas.
|
39
|
+
|
40
|
+
*Jens Ljungblad, Brian Bugh, Jon Palmer, Joel Hawksley*
|
41
|
+
|
42
|
+
# 2.11.1
|
43
|
+
|
44
|
+
* Fix kwarg warnings in Ruby 2.7.
|
45
|
+
|
46
|
+
*Joel Hawksley*
|
47
|
+
|
3
48
|
# 2.11.0
|
4
49
|
|
5
50
|
* Ensure Rails configuration is available within components.
|
data/README.md
CHANGED
@@ -160,6 +160,133 @@ Returning:
|
|
160
160
|
</div>
|
161
161
|
```
|
162
162
|
|
163
|
+
#### Slots (experimental)
|
164
|
+
|
165
|
+
_Slots are currently under development as a successor to Content Areas. The Slot APIs should be considered unfinished and subject to breaking changes in non-major releases of ViewComponent._
|
166
|
+
|
167
|
+
Slots enable multiple blocks of content to be passed to a single ViewComponent.
|
168
|
+
|
169
|
+
Slots exist in two forms: normal slots and collection slots.
|
170
|
+
|
171
|
+
Normal slots can be rendered once per component. They expose an accessor with the name of the slot that returns an instance of `ViewComponent::Slot`, etc.
|
172
|
+
|
173
|
+
Collection slots can be rendered multiple times. They expose an accessor with the pluralized name of the slot (`#rows`), which is an Array of `ViewComponent::Slot` instances.
|
174
|
+
|
175
|
+
To learn more about the design of the Slots API, see https://github.com/github/view_component/pull/348.
|
176
|
+
|
177
|
+
##### Defining Slots
|
178
|
+
|
179
|
+
Slots are defined by the `with_slot` macro:
|
180
|
+
|
181
|
+
`with_slot :header`
|
182
|
+
|
183
|
+
To define a collection slot, add `collection: true`:
|
184
|
+
|
185
|
+
`with_slot :row, collection: true`
|
186
|
+
|
187
|
+
To define a slot with a custom class, pass `class_name`:
|
188
|
+
|
189
|
+
`with_slot :body, class_name: 'BodySlot`
|
190
|
+
|
191
|
+
Slot classes should be subclasses of `ViewComponent::Slot`.
|
192
|
+
|
193
|
+
##### Example ViewComponent with Slots
|
194
|
+
|
195
|
+
`# box_component.rb`
|
196
|
+
```ruby
|
197
|
+
class BoxComponent < ViewComponent::Base
|
198
|
+
include ViewComponent::Slotable
|
199
|
+
|
200
|
+
with_slot :body, :footer
|
201
|
+
with_slot :header, class_name: "Header"
|
202
|
+
with_slot :row, collection: true, class_name: "Row"
|
203
|
+
|
204
|
+
class Header < ViewComponent::Slot
|
205
|
+
def initialize(class_names: "")
|
206
|
+
@class_names = class_names
|
207
|
+
end
|
208
|
+
|
209
|
+
def class_names
|
210
|
+
"Box-header #{@class_names}"
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
class Row < ViewComponent::Slot
|
215
|
+
def initialize(theme: :gray)
|
216
|
+
@theme = theme
|
217
|
+
end
|
218
|
+
|
219
|
+
def theme_class_name
|
220
|
+
case @theme
|
221
|
+
when :gray
|
222
|
+
"Box-row--gray"
|
223
|
+
when :hover_gray
|
224
|
+
"Box-row--hover-gray"
|
225
|
+
when :yellow
|
226
|
+
"Box-row--yellow"
|
227
|
+
when :blue
|
228
|
+
"Box-row--blue"
|
229
|
+
when :hover_blue
|
230
|
+
"Box-row--hover-blue"
|
231
|
+
else
|
232
|
+
"Box-row--gray"
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
```
|
238
|
+
|
239
|
+
`# box_component.html.erb`
|
240
|
+
```erb
|
241
|
+
<div class="Box">
|
242
|
+
<% if header %>
|
243
|
+
<div class="<%= header.class_names %>">
|
244
|
+
<%= header.content %>
|
245
|
+
</div>
|
246
|
+
<% end %>
|
247
|
+
<% if body %>
|
248
|
+
<div class="Box-body">
|
249
|
+
<%= body.content %>
|
250
|
+
</div>
|
251
|
+
<% end %>
|
252
|
+
<% if rows.any? %>
|
253
|
+
<ul>
|
254
|
+
<% rows.each do |row| %>
|
255
|
+
<li class="Box-row <%= row.theme_class_name %>">
|
256
|
+
<%= row.content %>
|
257
|
+
</li>
|
258
|
+
<% end %>
|
259
|
+
</ul>
|
260
|
+
<% end %>
|
261
|
+
<% if footer %>
|
262
|
+
<div class="Box-footer">
|
263
|
+
<%= footer %>
|
264
|
+
</div>
|
265
|
+
<% end %>
|
266
|
+
</div>
|
267
|
+
```
|
268
|
+
|
269
|
+
`# index.html.erb`
|
270
|
+
```erb
|
271
|
+
<%= render(BoxComponent.new) do |component| %>
|
272
|
+
<% component.slot(:header, class_names: "my-class-name") do %>
|
273
|
+
This is my header!
|
274
|
+
<% end %>
|
275
|
+
<% component.slot(:body) do %>
|
276
|
+
This is the body.
|
277
|
+
<% end %>
|
278
|
+
<% component.slot(:row) do %>
|
279
|
+
Row one
|
280
|
+
<% end %>
|
281
|
+
<% component.slot(:row, theme: :yellow) do %>
|
282
|
+
Yellow row
|
283
|
+
<% end %>
|
284
|
+
<% component.slot(:footer) do %>
|
285
|
+
This is the footer.
|
286
|
+
<% end %>
|
287
|
+
<% end %>
|
288
|
+
```
|
289
|
+
|
163
290
|
### Inline Component
|
164
291
|
|
165
292
|
ViewComponents can render without a template file, by defining a `call` method:
|
@@ -537,11 +664,11 @@ class TestComponentPreview < ViewComponent::Preview
|
|
537
664
|
end
|
538
665
|
```
|
539
666
|
|
540
|
-
Preview classes live in `test/components/previews`, which can be configured using the `
|
667
|
+
Preview classes live in `test/components/previews`, which can be configured using the `preview_paths` option:
|
541
668
|
|
542
669
|
`config/application.rb`
|
543
670
|
```ruby
|
544
|
-
config.view_component.
|
671
|
+
config.view_component.preview_paths << "#{Rails.root}/lib/component_previews"
|
545
672
|
```
|
546
673
|
|
547
674
|
Previews are served from <http://localhost:3000/rails/view_components> by default. To use a different endpoint, set the `preview_route` option:
|
@@ -581,7 +708,19 @@ To use component previews:
|
|
581
708
|
|
582
709
|
`config/application.rb`
|
583
710
|
```ruby
|
584
|
-
config.view_component.
|
711
|
+
config.view_component.preview_paths << "#{Rails.root}/spec/components/previews"
|
712
|
+
```
|
713
|
+
|
714
|
+
### Disabling the render monkey patch (Rails < 6.1)
|
715
|
+
|
716
|
+
In order to [avoid conflicts](https://github.com/github/view_component/issues/288) between ViewComponent and other gems that also monkey patch the `render` method, it is possible to configure ViewComponent to not include the render monkey patch:
|
717
|
+
|
718
|
+
`config.view_component.render_monkey_patch_enabled = false # defaults to true`
|
719
|
+
|
720
|
+
With the monkey patch disabled, use `render_component` (or `render_component_to_string`) instead:
|
721
|
+
|
722
|
+
```
|
723
|
+
<%= render_component Component.new(message: "bar") %>
|
585
724
|
```
|
586
725
|
|
587
726
|
### Sidecar assets (experimental)
|
@@ -731,7 +870,8 @@ ViewComponent is far from a novel idea! Popular implementations of view componen
|
|
731
870
|
## Resources
|
732
871
|
|
733
872
|
- [Encapsulating Views, RailsConf 2020](https://youtu.be/YVYRus_2KZM)
|
734
|
-
- [Rethinking the View Layer with Components
|
873
|
+
- [Rethinking the View Layer with Components, Ruby Rogues Podcast](https://devchat.tv/ruby-rogues/rr-461-rethinking-the-view-layer-with-components-with-joel-hawksley/)
|
874
|
+
- [ViewComponents in Action with Andrew Mason, Ruby on Rails Podcast](https://5by5.tv/rubyonrails/320)
|
735
875
|
- [ViewComponent at GitHub with Joel Hawksley](https://the-ruby-blend.fireside.fm/9)
|
736
876
|
- [Components, HAML vs ERB, and Design Systems](https://the-ruby-blend.fireside.fm/4)
|
737
877
|
- [Choosing the Right Tech Stack with Dave Paola](https://5by5.tv/rubyonrails/307)
|
@@ -784,10 +924,15 @@ ViewComponent is built by:
|
|
784
924
|
|@simonrand|@fugufish|@cover|@franks921|@fsateler|
|
785
925
|
|Dublin, Ireland|Salt Lake City, Utah|Barcelona|South Africa|Chile|
|
786
926
|
|
787
|
-
|<img src="https://avatars.githubusercontent.com/maxbeizer?s=256" alt="maxbeizer" width="128" />|<img src="https://avatars.githubusercontent.com/franco?s=256" alt="franco" width="128" />|<img src="https://avatars.githubusercontent.com/tbroad-ramsey?s=256" alt="tbroad-ramsey" width="128" />|
|
788
|
-
|
789
|
-
|@maxbeizer|@franco|@tbroad-ramsey|
|
790
|
-
|Nashville, TN|Switzerland|Spring Hill, TN|
|
927
|
+
|<img src="https://avatars.githubusercontent.com/maxbeizer?s=256" alt="maxbeizer" width="128" />|<img src="https://avatars.githubusercontent.com/franco?s=256" alt="franco" width="128" />|<img src="https://avatars.githubusercontent.com/tbroad-ramsey?s=256" alt="tbroad-ramsey" width="128" />|<img src="https://avatars.githubusercontent.com/jensljungblad?s=256" alt="jensljungblad" width="128" />|<img src="https://avatars.githubusercontent.com/bbugh?s=256" alt="bbugh" width="128" />|
|
928
|
+
|:---:|:---:|:---:|:---:|:---:|
|
929
|
+
|@maxbeizer|@franco|@tbroad-ramsey|@jensljungblad|@bbugh|
|
930
|
+
|Nashville, TN|Switzerland|Spring Hill, TN|New York, NY|Austin, TX|
|
931
|
+
|
932
|
+
|<img src="https://avatars.githubusercontent.com/johannesengl?s=256" alt="johannesengl" width="128" />|<img src="https://avatars.githubusercontent.com/czj?s=256" alt="czj" width="128" />|
|
933
|
+
|:---:|:---:|
|
934
|
+
|@johannesengl|@czj|
|
935
|
+
|Berlin, Germany|Paris, France|
|
791
936
|
|
792
937
|
## License
|
793
938
|
|
data/lib/view_component/base.rb
CHANGED
@@ -5,6 +5,7 @@ require "active_support/configurable"
|
|
5
5
|
require "view_component/collection"
|
6
6
|
require "view_component/compile_cache"
|
7
7
|
require "view_component/previewable"
|
8
|
+
require "view_component/slotable"
|
8
9
|
|
9
10
|
module ViewComponent
|
10
11
|
class Base < ActionView::Base
|
@@ -17,6 +18,10 @@ module ViewComponent
|
|
17
18
|
class_attribute :content_areas
|
18
19
|
self.content_areas = [] # class_attribute:default doesn't work until Rails 5.2
|
19
20
|
|
21
|
+
# Hash of registered Slots
|
22
|
+
class_attribute :slots
|
23
|
+
self.slots = {}
|
24
|
+
|
20
25
|
# Entrypoint for rendering components.
|
21
26
|
#
|
22
27
|
# view_context: ActionView context from calling view
|
@@ -157,12 +162,15 @@ module ViewComponent
|
|
157
162
|
mattr_accessor :test_controller
|
158
163
|
@@test_controller = "ApplicationController"
|
159
164
|
|
165
|
+
# Configure if render monkey patches should be included or not in Rails <6.1.
|
166
|
+
mattr_accessor :render_monkey_patch_enabled, instance_writer: false, default: true
|
167
|
+
|
160
168
|
class << self
|
161
169
|
attr_accessor :source_location
|
162
170
|
|
163
171
|
# Render a component collection.
|
164
|
-
def with_collection(
|
165
|
-
Collection.new(self,
|
172
|
+
def with_collection(collection, **args)
|
173
|
+
Collection.new(self, collection, **args)
|
166
174
|
end
|
167
175
|
|
168
176
|
# Provide identifier for ActionView template annotations
|
@@ -181,6 +189,10 @@ module ViewComponent
|
|
181
189
|
# has been re-defined by the consuming application, likely in ApplicationComponent.
|
182
190
|
child.source_location = caller_locations(1, 10).reject { |l| l.label == "inherited" }[0].absolute_path
|
183
191
|
|
192
|
+
# Clone slot configuration into child class
|
193
|
+
# see #test_slots_pollution
|
194
|
+
child.slots = self.slots.clone
|
195
|
+
|
184
196
|
super
|
185
197
|
end
|
186
198
|
|
@@ -9,7 +9,7 @@ module ViewComponent
|
|
9
9
|
@component.validate_collection_parameter!(validate_default: true)
|
10
10
|
|
11
11
|
@collection.map do |item|
|
12
|
-
content = @component.new(component_options(item, iterator)).render_in(view_context, &block)
|
12
|
+
content = @component.new(**component_options(item, iterator)).render_in(view_context, &block)
|
13
13
|
iterator.iterate!
|
14
14
|
content
|
15
15
|
end.join.html_safe
|
@@ -6,15 +6,24 @@ require "view_component"
|
|
6
6
|
module ViewComponent
|
7
7
|
class Engine < Rails::Engine # :nodoc:
|
8
8
|
config.view_component = ActiveSupport::OrderedOptions.new
|
9
|
+
config.view_component.preview_paths ||= []
|
9
10
|
|
10
11
|
initializer "view_component.set_configs" do |app|
|
11
12
|
options = app.config.view_component
|
12
13
|
|
14
|
+
options.render_monkey_patch_enabled = true if options.render_monkey_patch_enabled.nil?
|
13
15
|
options.show_previews = Rails.env.development? if options.show_previews.nil?
|
14
16
|
options.preview_route ||= ViewComponent::Base.preview_route
|
15
17
|
|
16
18
|
if options.show_previews
|
17
|
-
options.
|
19
|
+
options.preview_paths << "#{Rails.root}/test/components/previews" if defined?(Rails.root)
|
20
|
+
|
21
|
+
if options.preview_path.present?
|
22
|
+
ActiveSupport::Deprecation.warn(
|
23
|
+
"`preview_path` will be removed in v3.0.0. Use `preview_paths` instead."
|
24
|
+
)
|
25
|
+
options.preview_paths << options.preview_path
|
26
|
+
end
|
18
27
|
end
|
19
28
|
|
20
29
|
ActiveSupport.on_load(:view_component) do
|
@@ -42,21 +51,35 @@ module ViewComponent
|
|
42
51
|
end
|
43
52
|
end
|
44
53
|
|
45
|
-
initializer "view_component.monkey_patch_render" do
|
54
|
+
initializer "view_component.monkey_patch_render" do |app|
|
55
|
+
next if Rails.version.to_f >= 6.1 || !app.config.view_component.render_monkey_patch_enabled
|
56
|
+
|
46
57
|
ActiveSupport.on_load(:action_view) do
|
47
|
-
|
48
|
-
|
49
|
-
ActionView::Base.prepend ViewComponent::RenderMonkeyPatch
|
50
|
-
end
|
58
|
+
require "view_component/render_monkey_patch"
|
59
|
+
ActionView::Base.prepend ViewComponent::RenderMonkeyPatch
|
51
60
|
end
|
52
61
|
|
53
62
|
ActiveSupport.on_load(:action_controller) do
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
63
|
+
require "view_component/rendering_monkey_patch"
|
64
|
+
require "view_component/render_to_string_monkey_patch"
|
65
|
+
ActionController::Base.prepend ViewComponent::RenderingMonkeyPatch
|
66
|
+
ActionController::Base.prepend ViewComponent::RenderToStringMonkeyPatch
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
initializer "view_component.include_render_component" do |app|
|
71
|
+
next if Rails.version.to_f >= 6.1
|
72
|
+
|
73
|
+
ActiveSupport.on_load(:action_view) do
|
74
|
+
require "view_component/render_component_helper"
|
75
|
+
ActionView::Base.include ViewComponent::RenderComponentHelper
|
76
|
+
end
|
77
|
+
|
78
|
+
ActiveSupport.on_load(:action_controller) do
|
79
|
+
require "view_component/rendering_component_helper"
|
80
|
+
require "view_component/render_component_to_string_helper"
|
81
|
+
ActionController::Base.include ViewComponent::RenderingComponentHelper
|
82
|
+
ActionController::Base.include ViewComponent::RenderComponentToStringHelper
|
60
83
|
end
|
61
84
|
end
|
62
85
|
|
@@ -65,13 +65,13 @@ module ViewComponent # :nodoc:
|
|
65
65
|
private
|
66
66
|
|
67
67
|
def load_previews
|
68
|
-
|
68
|
+
Array(preview_paths).each do |preview_path|
|
69
69
|
Dir["#{preview_path}/**/*_preview.rb"].sort.each { |file| require_dependency file }
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
-
def
|
74
|
-
Base.
|
73
|
+
def preview_paths
|
74
|
+
Base.preview_paths
|
75
75
|
end
|
76
76
|
|
77
77
|
def show_previews
|
@@ -9,8 +9,11 @@ module ViewComponent # :nodoc:
|
|
9
9
|
included do
|
10
10
|
# Set the location of component previews through app configuration:
|
11
11
|
#
|
12
|
-
# config.view_component.
|
12
|
+
# config.view_component.preview_paths << "#{Rails.root}/lib/component_previews"
|
13
13
|
#
|
14
|
+
mattr_accessor :preview_paths, instance_writer: false
|
15
|
+
|
16
|
+
# TODO: deprecated, remove in v3.0.0
|
14
17
|
mattr_accessor :preview_path, instance_writer: false
|
15
18
|
|
16
19
|
# Enable or disable component previews through app configuration:
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/concern"
|
4
|
+
|
5
|
+
require "view_component/slot"
|
6
|
+
|
7
|
+
module ViewComponent
|
8
|
+
module Slotable
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
class_methods do
|
12
|
+
# support initializing slots as:
|
13
|
+
#
|
14
|
+
# with_slot(
|
15
|
+
# :header,
|
16
|
+
# collection: true|false,
|
17
|
+
# class_name: "Header" # class name string, used to instantiate Slot
|
18
|
+
# )
|
19
|
+
def with_slot(*slot_names, collection: false, class_name: nil)
|
20
|
+
slot_names.each do |slot_name|
|
21
|
+
# Ensure slot_name is not already declared
|
22
|
+
if self.slots.key?(slot_name)
|
23
|
+
raise ArgumentError.new("#{slot_name} slot declared multiple times")
|
24
|
+
end
|
25
|
+
|
26
|
+
# Ensure slot name is not :content
|
27
|
+
if slot_name == :content
|
28
|
+
raise ArgumentError.new ":content is a reserved slot name. Please use another name, such as ':body'"
|
29
|
+
end
|
30
|
+
|
31
|
+
# Set the name of the method used to access the Slot(s)
|
32
|
+
accessor_name =
|
33
|
+
if collection
|
34
|
+
# If Slot is a collection, set the accessor
|
35
|
+
# name to the pluralized form of the slot name
|
36
|
+
# For example: :tab => :tabs
|
37
|
+
ActiveSupport::Inflector.pluralize(slot_name)
|
38
|
+
else
|
39
|
+
slot_name
|
40
|
+
end
|
41
|
+
|
42
|
+
instance_variable_name = "@#{accessor_name}"
|
43
|
+
|
44
|
+
# If the slot is a collection, define an accesor that defaults to an empty array
|
45
|
+
if collection
|
46
|
+
class_eval <<-RUBY
|
47
|
+
def #{accessor_name}
|
48
|
+
#{instance_variable_name} ||= []
|
49
|
+
end
|
50
|
+
RUBY
|
51
|
+
else
|
52
|
+
attr_reader accessor_name
|
53
|
+
end
|
54
|
+
|
55
|
+
# Default class_name to ViewComponent::Slot
|
56
|
+
class_name = "ViewComponent::Slot" unless class_name.present?
|
57
|
+
|
58
|
+
# Register the slot on the component
|
59
|
+
self.slots[slot_name] = {
|
60
|
+
class_name: class_name,
|
61
|
+
instance_variable_name: instance_variable_name,
|
62
|
+
collection: collection
|
63
|
+
}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Build a Slot instance on a component,
|
69
|
+
# exposing it for use inside the
|
70
|
+
# component template.
|
71
|
+
#
|
72
|
+
# slot: Name of Slot, in symbol form
|
73
|
+
# **args: Arguments to be passed to Slot initializer
|
74
|
+
#
|
75
|
+
# For example:
|
76
|
+
# <%= render(SlotsComponent.new) do |component| %>
|
77
|
+
# <% component.slot(:footer, class_names: "footer-class") do %>
|
78
|
+
# <p>This is my footer!</p>
|
79
|
+
# <% end %>
|
80
|
+
# <% end %>
|
81
|
+
#
|
82
|
+
def slot(slot_name, **args, &block)
|
83
|
+
# Raise ArgumentError if `slot` does not exist
|
84
|
+
unless slots.keys.include?(slot_name)
|
85
|
+
raise ArgumentError.new "Unknown slot '#{slot_name}' - expected one of '#{slots.keys}'"
|
86
|
+
end
|
87
|
+
|
88
|
+
slot = slots[slot_name]
|
89
|
+
|
90
|
+
# The class name of the Slot, such as Header
|
91
|
+
slot_class = self.class.const_get(slot[:class_name])
|
92
|
+
|
93
|
+
unless slot_class <= ViewComponent::Slot
|
94
|
+
raise ArgumentError.new "#{slot[:class_name]} must inherit from ViewComponent::Slot"
|
95
|
+
end
|
96
|
+
|
97
|
+
# Instantiate Slot class, accommodating Slots that don't accept arguments
|
98
|
+
slot_instance = args.present? ? slot_class.new(**args) : slot_class.new
|
99
|
+
|
100
|
+
# Capture block and assign to slot_instance#content
|
101
|
+
slot_instance.content = view_context.capture(&block) if block_given?
|
102
|
+
|
103
|
+
if slot[:collection]
|
104
|
+
# Initialize instance variable as an empty array
|
105
|
+
# if slot is a collection and has yet to be initialized
|
106
|
+
unless instance_variable_defined?(slot[:instance_variable_name])
|
107
|
+
instance_variable_set(slot[:instance_variable_name], [])
|
108
|
+
end
|
109
|
+
|
110
|
+
# Append Slot instance to collection accessor Array
|
111
|
+
instance_variable_get(slot[:instance_variable_name]) << slot_instance
|
112
|
+
else
|
113
|
+
# Assign the Slot instance to the slot accessor
|
114
|
+
instance_variable_set(slot[:instance_variable_name], slot_instance)
|
115
|
+
end
|
116
|
+
|
117
|
+
# Return nil, as this method should not output anything to the view itself.
|
118
|
+
nil
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -14,13 +14,18 @@ module ViewComponent
|
|
14
14
|
assert_no_selector("body")
|
15
15
|
end
|
16
16
|
rescue LoadError
|
17
|
-
warn "WARNING in `ViewComponent::TestHelpers`: You must add `capybara` to your Gemfile to use Capybara assertions."
|
17
|
+
warn "WARNING in `ViewComponent::TestHelpers`: You must add `capybara` to your Gemfile to use Capybara assertions." if ENV["DEBUG"]
|
18
18
|
end
|
19
19
|
|
20
20
|
attr_reader :rendered_component
|
21
21
|
|
22
22
|
def render_inline(component, **args, &block)
|
23
|
-
@rendered_component =
|
23
|
+
@rendered_component =
|
24
|
+
if Rails.version.to_f >= 6.1
|
25
|
+
controller.view_context.render(component, args, &block)
|
26
|
+
else
|
27
|
+
controller.view_context.render_component(component, &block)
|
28
|
+
end
|
24
29
|
|
25
30
|
Nokogiri::HTML.fragment(@rendered_component)
|
26
31
|
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.14.1
|
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: 2020-
|
11
|
+
date: 2020-07-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -204,9 +204,14 @@ files:
|
|
204
204
|
- lib/view_component/engine.rb
|
205
205
|
- lib/view_component/preview.rb
|
206
206
|
- lib/view_component/previewable.rb
|
207
|
+
- lib/view_component/render_component_helper.rb
|
208
|
+
- lib/view_component/render_component_to_string_helper.rb
|
207
209
|
- lib/view_component/render_monkey_patch.rb
|
208
210
|
- lib/view_component/render_to_string_monkey_patch.rb
|
211
|
+
- lib/view_component/rendering_component_helper.rb
|
209
212
|
- lib/view_component/rendering_monkey_patch.rb
|
213
|
+
- lib/view_component/slot.rb
|
214
|
+
- lib/view_component/slotable.rb
|
210
215
|
- lib/view_component/template_error.rb
|
211
216
|
- lib/view_component/test_case.rb
|
212
217
|
- lib/view_component/test_helpers.rb
|