actionview-component 1.9.0 → 1.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE +2 -0
- data/CHANGELOG.md +48 -0
- data/Gemfile.lock +19 -4
- data/README.md +56 -74
- data/actionview-component.gemspec +2 -1
- data/{lib/railties/lib → app/controllers}/rails/components_controller.rb +10 -4
- data/lib/action_view/component.rb +2 -1
- data/lib/action_view/component/base.rb +21 -22
- data/lib/action_view/component/engine.rb +67 -0
- data/lib/action_view/component/railtie.rb +1 -63
- data/lib/action_view/component/render_monkey_patch.rb +11 -6
- data/lib/action_view/component/rendering_monkey_patch.rb +15 -0
- data/lib/action_view/component/test_helpers.rb +11 -1
- data/lib/action_view/component/version.rb +1 -1
- data/lib/rails/generators/component/component_generator.rb +7 -3
- data/lib/rails/generators/erb/component_generator.rb +27 -0
- data/lib/rails/generators/{component → erb}/templates/component.html.erb.tt +0 -0
- data/lib/rails/generators/haml/component_generator.rb +27 -0
- data/lib/rails/generators/haml/templates/component.html.haml.tt +5 -0
- data/lib/rails/generators/slim/component_generator.rb +27 -0
- data/lib/rails/generators/slim/templates/component.html.slim +5 -0
- metadata +27 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0521a37d11215c6cb0c08a78054dd57a4bdf53ebea65935908611f73264a1727
|
4
|
+
data.tar.gz: 470a3bdcfb35dcb37162ec708b22491d66f7d1772f40a483a160ed6b49477e3c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d92b3636294971bb68eadbc7bf53799642d2407de53cd2d492fec6f1723e96668db1d030043e6c7a3fa0f04b484b72f70d5104dbb252ffbcf4efad02e82cdf78
|
7
|
+
data.tar.gz: 8b24889733157c2c8890362af41881047a81ae3bd0677d9fb6528ced72dd6505ee1fc12607ee120f978ce7933a7a4d2d000e0e4de3d7e76998df341646c2f1f8
|
data/.github/ISSUE_TEMPLATE
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,51 @@
|
|
1
|
+
# master
|
2
|
+
|
3
|
+
# v1.13.0
|
4
|
+
|
5
|
+
* Allow components to be rendered inside controllers.
|
6
|
+
|
7
|
+
*Joel Hawksley*
|
8
|
+
|
9
|
+
* Improve backtraces from exceptions raised in templates.
|
10
|
+
|
11
|
+
*Blake Williams*
|
12
|
+
|
13
|
+
# v1.12.0
|
14
|
+
|
15
|
+
* Revert: Remove initializer requirement for Ruby 2.7+
|
16
|
+
|
17
|
+
*Joel Hawksley*
|
18
|
+
|
19
|
+
* Restructure Railtie into Engine
|
20
|
+
|
21
|
+
*Sean Doyle*
|
22
|
+
|
23
|
+
* Allow components to override before_render_check
|
24
|
+
|
25
|
+
*Joel Hawksley*
|
26
|
+
|
27
|
+
# v1.11.1
|
28
|
+
|
29
|
+
* Relax Capybara requirement.
|
30
|
+
|
31
|
+
*Joel Hawksley*
|
32
|
+
|
33
|
+
# v1.11.0
|
34
|
+
|
35
|
+
* Add support for Capybara matchers.
|
36
|
+
|
37
|
+
*Joel Hawksley*
|
38
|
+
|
39
|
+
* Add erb, haml, & slim template generators
|
40
|
+
|
41
|
+
*Asger Behncke Jacobsen*
|
42
|
+
|
43
|
+
# v1.10.0
|
44
|
+
|
45
|
+
* Deprecate all `render` syntaxes except for `render(MyComponent.new(foo: :bar))`
|
46
|
+
|
47
|
+
*Joel Hawksley*
|
48
|
+
|
1
49
|
# v1.9.0
|
2
50
|
|
3
51
|
* Remove initializer requirement for Ruby 2.7+
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
actionview-component (1.
|
4
|
+
actionview-component (1.13.0)
|
5
|
+
capybara (>= 3)
|
5
6
|
|
6
7
|
GEM
|
7
8
|
remote: https://rubygems.org/
|
@@ -61,6 +62,8 @@ GEM
|
|
61
62
|
minitest (~> 5.1)
|
62
63
|
tzinfo (~> 1.1)
|
63
64
|
zeitwerk (~> 2.1, >= 2.1.8)
|
65
|
+
addressable (2.7.0)
|
66
|
+
public_suffix (>= 2.0.2, < 5.0)
|
64
67
|
ast (2.4.0)
|
65
68
|
better_html (1.0.14)
|
66
69
|
actionview (>= 4.0)
|
@@ -71,6 +74,14 @@ GEM
|
|
71
74
|
parser (>= 2.4)
|
72
75
|
smart_properties
|
73
76
|
builder (3.2.3)
|
77
|
+
capybara (3.31.0)
|
78
|
+
addressable
|
79
|
+
mini_mime (>= 0.1.3)
|
80
|
+
nokogiri (~> 1.8)
|
81
|
+
rack (>= 1.6.0)
|
82
|
+
rack-test (>= 0.6.3)
|
83
|
+
regexp_parser (~> 1.5)
|
84
|
+
xpath (~> 3.2)
|
74
85
|
concurrent-ruby (1.1.5)
|
75
86
|
crass (1.0.5)
|
76
87
|
erubi (1.8.0)
|
@@ -96,11 +107,12 @@ GEM
|
|
96
107
|
mini_portile2 (2.4.0)
|
97
108
|
minitest (5.1.0)
|
98
109
|
nio4r (2.5.2)
|
99
|
-
nokogiri (1.10.
|
110
|
+
nokogiri (1.10.8)
|
100
111
|
mini_portile2 (~> 2.4.0)
|
101
112
|
parallel (1.17.0)
|
102
113
|
parser (2.6.3.0)
|
103
114
|
ast (~> 2.4.0)
|
115
|
+
public_suffix (4.0.3)
|
104
116
|
rack (2.0.8)
|
105
117
|
rack-test (1.1.0)
|
106
118
|
rack (>= 1.0, < 3)
|
@@ -131,7 +143,8 @@ GEM
|
|
131
143
|
rake (>= 0.8.7)
|
132
144
|
thor (>= 0.20.3, < 2.0)
|
133
145
|
rainbow (3.0.0)
|
134
|
-
rake (
|
146
|
+
rake (13.0.1)
|
147
|
+
regexp_parser (1.7.0)
|
135
148
|
rubocop (0.74.0)
|
136
149
|
jaro_winkler (~> 1.5.1)
|
137
150
|
parallel (~> 1.10)
|
@@ -166,6 +179,8 @@ GEM
|
|
166
179
|
websocket-driver (0.7.1)
|
167
180
|
websocket-extensions (>= 0.1.0)
|
168
181
|
websocket-extensions (0.1.4)
|
182
|
+
xpath (3.2.0)
|
183
|
+
nokogiri (~> 1.8)
|
169
184
|
zeitwerk (2.1.10)
|
170
185
|
|
171
186
|
PLATFORMS
|
@@ -178,7 +193,7 @@ DEPENDENCIES
|
|
178
193
|
haml (~> 5)
|
179
194
|
minitest (= 5.1.0)
|
180
195
|
rails (= 6.0.0)
|
181
|
-
rake (~>
|
196
|
+
rake (~> 13.0)
|
182
197
|
rubocop (= 0.74)
|
183
198
|
rubocop-github (~> 0.13.0)
|
184
199
|
slim (~> 4.0)
|
data/README.md
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
_Note: This gem is in the process of a name / API change, see https://github.com/github/actionview-component/issues/206_
|
2
|
+
|
3
|
+
_You are viewing the README for the development version of ActionView::Component. If you are using the current release version you can find the README at https://github.com/github/actionview-component/blob/v1.11.1/README.md_
|
4
|
+
|
1
5
|
# ActionView::Component
|
2
6
|
`ActionView::Component` is a framework for building view components in Rails.
|
3
7
|
|
@@ -5,17 +9,17 @@
|
|
5
9
|
|
6
10
|
## Roadmap
|
7
11
|
|
8
|
-
|
12
|
+
Support for third-party component frameworks was merged into Rails `6.1.0.alpha` in https://github.com/rails/rails/pull/36388 and https://github.com/rails/rails/pull/37919. Our goal with this project is to provide a first-class component framework for this new capability in Rails.
|
9
13
|
|
10
|
-
|
14
|
+
This gem includes a backport of those changes for Rails `5.0.0` through `6.1.0.alpha`.
|
11
15
|
|
12
16
|
## Design philosophy
|
13
17
|
|
14
|
-
|
18
|
+
This library is designed to integrate as seamlessly as possible with Rails, with the [least surprise](https://www.artima.com/intv/ruby4.html).
|
15
19
|
|
16
20
|
## Compatibility
|
17
21
|
|
18
|
-
`actionview-component` is tested for compatibility with combinations of Ruby `2.5`/`2.6` and Rails `5.0.0`/`5.2.3`/`6.0.0`/`6.1.0.alpha`.
|
22
|
+
`actionview-component` is tested for compatibility with combinations of Ruby `2.5`/`2.6`/`2.7` and Rails `5.0.0`/`5.2.3`/`6.0.0`/`6.1.0.alpha`.
|
19
23
|
|
20
24
|
## Installation
|
21
25
|
Add this line to your application's Gemfile:
|
@@ -75,24 +79,14 @@ Our views often fail even the most basic standards of code quality we expect out
|
|
75
79
|
|
76
80
|
By clearly defining the context necessary to render a component, we’ve found them to be easier to reuse than partials.
|
77
81
|
|
78
|
-
#### Performance
|
79
|
-
|
80
|
-
In early benchmarks, we’ve seen performance improvements over the existing rendering pipeline. For a test page with nested renders 10 levels deep, we’re seeing around a 5x increase in speed over partials:
|
81
|
-
|
82
|
-
```
|
83
|
-
Comparison:
|
84
|
-
component: 6515.4 i/s
|
85
|
-
partial: 1251.2 i/s - 5.21x slower
|
86
|
-
```
|
87
|
-
|
88
|
-
_Rails 6.1.0.alpha, [joelhawksley/actionview-component-demo](https://github.com/joelhawksley/actionview-component-demo), /benchmark route, via `RAILS_ENV=production rails s`, measured with [evanphx/benchmark-ips](https://github.com/evanphx/benchmark-ips)_
|
89
|
-
|
90
82
|
### When should I use components?
|
91
83
|
|
92
84
|
Components are most effective in cases where view code is reused or needs to be tested directly.
|
93
85
|
|
94
86
|
### Building components
|
95
87
|
|
88
|
+
#### Conventions
|
89
|
+
|
96
90
|
Components are subclasses of `ActionView::Component::Base` and live in `app/components`. You may wish to create an `ApplicationComponent` that is a subclass of `ActionView::Component::Base` and inherit from that instead.
|
97
91
|
|
98
92
|
Component class names end in -`Component`.
|
@@ -117,6 +111,18 @@ bin/rails generate component Example title content
|
|
117
111
|
create app/components/example_component.html.erb
|
118
112
|
```
|
119
113
|
|
114
|
+
`ActionView::Component` includes template generators for the `erb`, `haml`, and `slim` template engines and will use the template engine specified in your Rails config (`config.generators.template_engine`) by default.
|
115
|
+
|
116
|
+
If you want to override this behavior, you can pass the template engine as an option to the generator:
|
117
|
+
|
118
|
+
```bash
|
119
|
+
bin/rails generate component Example title content --template-engine slim
|
120
|
+
invoke test_unit
|
121
|
+
create test/components/example_component_test.rb
|
122
|
+
create app/components/example_component.rb
|
123
|
+
create app/components/example_component.html.slim
|
124
|
+
```
|
125
|
+
|
120
126
|
#### Implementation
|
121
127
|
|
122
128
|
An `ActionView::Component` is a Ruby file and corresponding template file (in any format supported by Rails) with the same base name:
|
@@ -144,7 +150,7 @@ end
|
|
144
150
|
We can render it in a view as:
|
145
151
|
|
146
152
|
```erb
|
147
|
-
<%= render(TestComponent
|
153
|
+
<%= render(TestComponent.new(title: "my title")) do %>
|
148
154
|
Hello, World!
|
149
155
|
<% end %>
|
150
156
|
```
|
@@ -155,42 +161,12 @@ Which returns:
|
|
155
161
|
<span title="my title">Hello, World!</span>
|
156
162
|
```
|
157
163
|
|
158
|
-
##### Supported `render` syntaxes
|
159
|
-
|
160
|
-
Components can be rendered via:
|
161
|
-
|
162
|
-
`render(TestComponent, foo: :bar)`
|
163
|
-
|
164
|
-
`render(component: TestComponent, locals: { foo: :bar })`
|
165
|
-
|
166
|
-
**Rendering components through models**
|
167
|
-
|
168
|
-
Passing model instances will cause `render` to look for its respective component class.
|
169
|
-
|
170
|
-
The component is instantiated with the rendered model instance.
|
171
|
-
|
172
|
-
Example for a `Post` model:
|
173
|
-
|
174
|
-
`render(@post)`
|
175
|
-
|
176
|
-
```ruby
|
177
|
-
class PostComponent < ActionView::Component::Base
|
178
|
-
def initialize(post)
|
179
|
-
@post = post
|
180
|
-
end
|
181
|
-
end
|
182
|
-
```
|
183
|
-
|
184
|
-
The following syntax has been deprecated and will be removed in v2.0.0:
|
185
|
-
|
186
|
-
`render(TestComponent.new(foo: :bar))`
|
187
|
-
|
188
164
|
#### Error case
|
189
165
|
|
190
166
|
If the component is rendered with a blank title:
|
191
167
|
|
192
168
|
```erb
|
193
|
-
<%= render(TestComponent
|
169
|
+
<%= render(TestComponent.new(title: "")) do %>
|
194
170
|
Hello, World!
|
195
171
|
<% end %>
|
196
172
|
```
|
@@ -213,6 +189,8 @@ class ModalComponent < ActionView::Component::Base
|
|
213
189
|
def initialize(user:)
|
214
190
|
@user = user
|
215
191
|
end
|
192
|
+
|
193
|
+
attr_reader :user
|
216
194
|
end
|
217
195
|
```
|
218
196
|
|
@@ -220,16 +198,16 @@ end
|
|
220
198
|
```erb
|
221
199
|
<div class="modal">
|
222
200
|
<div class="header"><%= header %></div>
|
223
|
-
<div class="body"><%= body
|
201
|
+
<div class="body"><%= body %></div>
|
224
202
|
</div>
|
225
203
|
```
|
226
204
|
|
227
205
|
We can render it in a view as:
|
228
206
|
|
229
207
|
```erb
|
230
|
-
<%= render(ModalComponent
|
208
|
+
<%= render(ModalComponent.new(user: {name: 'Jane'})) do |component| %>
|
231
209
|
<% component.with(:header) do %>
|
232
|
-
Hello <%= user[:name] %>
|
210
|
+
Hello <%= component.user[:name] %>
|
233
211
|
<% end %>
|
234
212
|
<% component.with(:body) do %>
|
235
213
|
<p>Have a great day.</p>
|
@@ -265,8 +243,8 @@ end
|
|
265
243
|
```
|
266
244
|
|
267
245
|
```erb
|
268
|
-
<%= render(ModalComponent
|
269
|
-
<%
|
246
|
+
<%= render(ModalComponent.new(header: "Hi!")) do |component| %>
|
247
|
+
<% component.with(:header) do %>
|
270
248
|
<span class="help_icon"><%= component.header %></span>
|
271
249
|
<% end %>
|
272
250
|
<% component.with(:body) do %>
|
@@ -292,7 +270,7 @@ end
|
|
292
270
|
|
293
271
|
`app/views/render_arg.html.erb`:
|
294
272
|
```erb
|
295
|
-
<%= render(ModalComponent
|
273
|
+
<%= render(ModalComponent.new(header: "Hi!")) do |component| %>
|
296
274
|
<% component.with(:body) do %>
|
297
275
|
<p>Have a great day.</p>
|
298
276
|
<% end %>
|
@@ -332,13 +310,13 @@ end
|
|
332
310
|
<% if header %>
|
333
311
|
<div class="header"><%= header %></div>
|
334
312
|
<% end %>
|
335
|
-
<div class="body"><%= body
|
313
|
+
<div class="body"><%= body %></div>
|
336
314
|
</div>
|
337
315
|
```
|
338
316
|
|
339
317
|
`app/views/render_arg.html.erb`:
|
340
318
|
```erb
|
341
|
-
<%= render(ModalComponent
|
319
|
+
<%= render(ModalComponent.new(header: "Hi!")) do |component| %>
|
342
320
|
<% component.with(:body) do %>
|
343
321
|
<p>Have a great day.</p>
|
344
322
|
<% end %>
|
@@ -347,7 +325,7 @@ end
|
|
347
325
|
|
348
326
|
`app/views/with_block.html.erb`:
|
349
327
|
```erb
|
350
|
-
<%= render(ModalComponent) do |component| %>
|
328
|
+
<%= render(ModalComponent.new) do |component| %>
|
351
329
|
<% component.with(:header) do %>
|
352
330
|
<span class="help_icon">Hello</span>
|
353
331
|
<% end %>
|
@@ -359,7 +337,7 @@ end
|
|
359
337
|
|
360
338
|
`app/views/no_header.html.erb`:
|
361
339
|
```erb
|
362
|
-
<%= render(ModalComponent) do |component| %>
|
340
|
+
<%= render(ModalComponent.new) do |component| %>
|
363
341
|
<% component.with(:body) do %>
|
364
342
|
<p>Have a great day.</p>
|
365
343
|
<% end %>
|
@@ -386,7 +364,7 @@ or the view that renders the component:
|
|
386
364
|
```erb
|
387
365
|
<!-- app/views/_banners.html.erb -->
|
388
366
|
<% if current_user.requires_confirmation? %>
|
389
|
-
<%= render(ConfirmEmailComponent
|
367
|
+
<%= render(ConfirmEmailComponent.new(user: current_user)) %>
|
390
368
|
<% end %>
|
391
369
|
```
|
392
370
|
|
@@ -394,7 +372,7 @@ The `#render?` hook allows you to move this logic into the Ruby class, leaving y
|
|
394
372
|
|
395
373
|
```ruby
|
396
374
|
# app/components/confirm_email_component.rb
|
397
|
-
class ConfirmEmailComponent <
|
375
|
+
class ConfirmEmailComponent < ActionView::Component::Base
|
398
376
|
def initialize(user:)
|
399
377
|
@user = user
|
400
378
|
end
|
@@ -402,6 +380,8 @@ class ConfirmEmailComponent < ApplicationComponent
|
|
402
380
|
def render?
|
403
381
|
@user.requires_confirmation?
|
404
382
|
end
|
383
|
+
|
384
|
+
attr_reader :user
|
405
385
|
end
|
406
386
|
```
|
407
387
|
|
@@ -414,22 +394,21 @@ end
|
|
414
394
|
|
415
395
|
```erb
|
416
396
|
<!-- app/views/_banners.html.erb -->
|
417
|
-
<%= render(ConfirmEmailComponent
|
397
|
+
<%= render(ConfirmEmailComponent.new(user: current_user)) %>
|
418
398
|
```
|
419
399
|
|
420
400
|
### Testing
|
421
401
|
|
422
|
-
Components are unit tested directly. The `render_inline` test helper
|
402
|
+
Components are unit tested directly. The `render_inline` test helper is compatible with Capybara matchers, allowing us to test the component above as:
|
423
403
|
|
424
404
|
```ruby
|
425
405
|
require "action_view/component/test_case"
|
426
406
|
|
427
407
|
class MyComponentTest < ActionView::Component::TestCase
|
428
408
|
test "render component" do
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
)
|
409
|
+
render_inline(TestComponent.new(title: "my title")) { "Hello, World!" }
|
410
|
+
|
411
|
+
assert_selector("span[title='my title']", "Hello, World!")
|
433
412
|
end
|
434
413
|
end
|
435
414
|
```
|
@@ -443,10 +422,9 @@ To test a specific variant you can wrap your test with the `with_variant` helper
|
|
443
422
|
```ruby
|
444
423
|
test "render component for tablet" do
|
445
424
|
with_variant :tablet do
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
)
|
425
|
+
render_inline(TestComponent.new(title: "my title")) { "Hello, tablets!" }
|
426
|
+
|
427
|
+
assert_selector("span[title='my title']", "Hello, tablets!")
|
450
428
|
end
|
451
429
|
end
|
452
430
|
```
|
@@ -462,11 +440,11 @@ You can define as many examples as you want:
|
|
462
440
|
|
463
441
|
class TestComponentPreview < ActionView::Component::Preview
|
464
442
|
def with_default_title
|
465
|
-
render(TestComponent
|
443
|
+
render(TestComponent.new(title: "Test component default"))
|
466
444
|
end
|
467
445
|
|
468
446
|
def with_long_title
|
469
|
-
render(TestComponent
|
447
|
+
render(TestComponent.new(title: "This is a really long title to see how the component renders this"))
|
470
448
|
end
|
471
449
|
end
|
472
450
|
```
|
@@ -530,8 +508,7 @@ config.action_view_component.preview_path = "#{Rails.root}/spec/components/previ
|
|
530
508
|
|
531
509
|
### Initializer requirement
|
532
510
|
|
533
|
-
|
534
|
-
However, `initialize` is no longer required for projects using 2.7.x and above.
|
511
|
+
ActionView::Component requires the presence of an `initialize` method in each component.
|
535
512
|
|
536
513
|
## Frequently Asked Questions
|
537
514
|
|
@@ -593,6 +570,11 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/github
|
|
593
570
|
|@mellowfish|@horacio|@dukex|@dark-panda|@smashwilson|
|
594
571
|
|Spring Hill, TN|Buenos Aires|São Paulo||Gambrills, MD|
|
595
572
|
|
573
|
+
|<img src="https://avatars.githubusercontent.com/blakewilliams?s=256" alt="blakewilliams" width="128" />|
|
574
|
+
|:---:|
|
575
|
+
|@blakewilliams|
|
576
|
+
|Boston, MA|
|
577
|
+
|
596
578
|
## License
|
597
579
|
|
598
580
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
@@ -34,8 +34,9 @@ Gem::Specification.new do |spec|
|
|
34
34
|
|
35
35
|
spec.required_ruby_version = ">= 2.3.0"
|
36
36
|
|
37
|
+
spec.add_runtime_dependency "capybara", ">= 3"
|
37
38
|
spec.add_development_dependency "bundler", ">= 1.14"
|
38
|
-
spec.add_development_dependency "rake", "~>
|
39
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
39
40
|
spec.add_development_dependency "minitest", "= 5.1.0"
|
40
41
|
spec.add_development_dependency "haml", "~> 5"
|
41
42
|
spec.add_development_dependency "slim", "~> 4.0"
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require "rails/application_controller"
|
4
4
|
|
5
5
|
class Rails::ComponentsController < Rails::ApplicationController # :nodoc:
|
6
|
-
prepend_view_path File.expand_path("templates/rails", __dir__)
|
6
|
+
prepend_view_path File.expand_path("../../../lib/railties/lib/rails/templates/rails", __dir__)
|
7
7
|
prepend_view_path "#{Rails.root}/app/views/" if defined?(Rails.root)
|
8
8
|
|
9
9
|
around_action :set_locale, only: :previews
|
@@ -17,19 +17,25 @@ class Rails::ComponentsController < Rails::ApplicationController # :nodoc:
|
|
17
17
|
def index
|
18
18
|
@previews = ActionView::Component::Preview.all
|
19
19
|
@page_title = "Component Previews"
|
20
|
-
|
20
|
+
# rubocop:disable GitHub/RailsControllerRenderPathsExist
|
21
|
+
render "components/index"
|
22
|
+
# rubocop:enable GitHub/RailsControllerRenderPathsExist
|
21
23
|
end
|
22
24
|
|
23
25
|
def previews
|
24
26
|
if params[:path] == @preview.preview_name
|
25
27
|
@page_title = "Component Previews for #{@preview.preview_name}"
|
26
|
-
|
28
|
+
# rubocop:disable GitHub/RailsControllerRenderPathsExist
|
29
|
+
render "components/previews"
|
30
|
+
# rubocop:enable GitHub/RailsControllerRenderPathsExist
|
27
31
|
else
|
28
32
|
@example_name = File.basename(params[:path])
|
29
33
|
@render_args = @preview.render_args(@example_name)
|
30
34
|
layout = @render_args[:layout]
|
31
35
|
opts = layout.nil? ? {} : { layout: layout }
|
32
|
-
|
36
|
+
# rubocop:disable GitHub/RailsControllerRenderPathsExist
|
37
|
+
render "components/preview", **opts
|
38
|
+
# rubocop:enable GitHub/RailsControllerRenderPathsExist
|
33
39
|
end
|
34
40
|
end
|
35
41
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require "active_model"
|
4
4
|
require "action_view"
|
5
5
|
require "active_support/dependencies/autoload"
|
6
|
-
require "action_view/component/
|
6
|
+
require "action_view/component/engine"
|
7
7
|
|
8
8
|
module ActionView
|
9
9
|
module Component
|
@@ -16,6 +16,7 @@ module ActionView
|
|
16
16
|
autoload :TestHelpers
|
17
17
|
autoload :TestCase
|
18
18
|
autoload :RenderMonkeyPatch
|
19
|
+
autoload :RenderingMonkeyPatch
|
19
20
|
autoload :TemplateError
|
20
21
|
end
|
21
22
|
end
|
@@ -14,10 +14,9 @@ module ActionView
|
|
14
14
|
class_attribute :content_areas, default: []
|
15
15
|
self.content_areas = [] # default doesn't work until Rails 5.2
|
16
16
|
|
17
|
-
# Entrypoint for rendering components.
|
17
|
+
# Entrypoint for rendering components.
|
18
18
|
#
|
19
19
|
# view_context: ActionView context from calling view
|
20
|
-
# args(hash): params to be passed to component being rendered
|
21
20
|
# block: optional block to be captured within the view context
|
22
21
|
#
|
23
22
|
# returns HTML that has been escaped by the respective template handler
|
@@ -35,11 +34,11 @@ module ActionView
|
|
35
34
|
# <span title="<%= @title %>">Hello, <%= content %>!</span>
|
36
35
|
#
|
37
36
|
# In use:
|
38
|
-
# <%= render MyComponent
|
37
|
+
# <%= render MyComponent.new(title: "greeting") do %>world<% end %>
|
39
38
|
# returns:
|
40
39
|
# <span title="greeting">Hello, world!</span>
|
41
40
|
#
|
42
|
-
def render_in(view_context,
|
41
|
+
def render_in(view_context, &block)
|
43
42
|
self.class.compile!
|
44
43
|
@view_context = view_context
|
45
44
|
@view_renderer ||= view_context.view_renderer
|
@@ -53,15 +52,21 @@ module ActionView
|
|
53
52
|
|
54
53
|
@content = view_context.capture(self, &block) if block_given?
|
55
54
|
|
56
|
-
|
57
|
-
|
58
|
-
return "" unless render?
|
55
|
+
before_render_check
|
59
56
|
|
60
|
-
|
57
|
+
if render?
|
58
|
+
send(self.class.call_method_name(@variant))
|
59
|
+
else
|
60
|
+
""
|
61
|
+
end
|
61
62
|
ensure
|
62
63
|
@current_template = old_current_template
|
63
64
|
end
|
64
65
|
|
66
|
+
def before_render_check
|
67
|
+
validate!
|
68
|
+
end
|
69
|
+
|
65
70
|
def render?
|
66
71
|
true
|
67
72
|
end
|
@@ -142,14 +147,12 @@ module ActionView
|
|
142
147
|
|
143
148
|
def source_location
|
144
149
|
@source_location ||=
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
initialize_method.source_location[0] if initialize_method.owner == self
|
152
|
-
end
|
150
|
+
begin
|
151
|
+
# Require `#initialize` to be defined so that we can use `method#source_location`
|
152
|
+
# to look up the filename of the component.
|
153
|
+
initialize_method = instance_method(:initialize)
|
154
|
+
initialize_method.source_location[0] if initialize_method.owner == self
|
155
|
+
end
|
153
156
|
end
|
154
157
|
|
155
158
|
def compiled?
|
@@ -172,7 +175,7 @@ module ActionView
|
|
172
175
|
end
|
173
176
|
|
174
177
|
templates.each do |template|
|
175
|
-
class_eval <<-RUBY,
|
178
|
+
class_eval <<-RUBY, template[:path], -1
|
176
179
|
def #{call_method_name(template[:variant])}
|
177
180
|
@output_buffer = ActionView::OutputBuffer.new
|
178
181
|
#{compiled_template(template[:path])}
|
@@ -206,10 +209,6 @@ module ActionView
|
|
206
209
|
|
207
210
|
private
|
208
211
|
|
209
|
-
def const_source_location_supported?
|
210
|
-
respond_to? :const_source_location # introduced in Ruby 2.7
|
211
|
-
end
|
212
|
-
|
213
212
|
def matching_views_in_source_location
|
214
213
|
return [] unless source_location
|
215
214
|
(Dir["#{source_location.chomp(File.extname(source_location))}.*{#{ActionView::Template.template_handler_extensions.join(',')}}"] - [source_location])
|
@@ -232,7 +231,7 @@ module ActionView
|
|
232
231
|
@template_errors ||=
|
233
232
|
begin
|
234
233
|
errors = []
|
235
|
-
if source_location.nil?
|
234
|
+
if source_location.nil?
|
236
235
|
# Require `#initialize` to be defined so that we can use `method#source_location`
|
237
236
|
# to look up the filename of the component.
|
238
237
|
errors << "#{self} must implement #initialize."
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails"
|
4
|
+
require "action_view/component"
|
5
|
+
|
6
|
+
module ActionView
|
7
|
+
module Component
|
8
|
+
class Engine < Rails::Engine # :nodoc:
|
9
|
+
config.action_view_component = ActiveSupport::OrderedOptions.new
|
10
|
+
|
11
|
+
initializer "action_view_component.set_configs" do |app|
|
12
|
+
options = app.config.action_view_component
|
13
|
+
|
14
|
+
options.show_previews = Rails.env.development? if options.show_previews.nil?
|
15
|
+
|
16
|
+
if options.show_previews
|
17
|
+
options.preview_path ||= defined?(Rails.root) ? "#{Rails.root}/test/components/previews" : nil
|
18
|
+
end
|
19
|
+
|
20
|
+
ActiveSupport.on_load(:action_view_component) do
|
21
|
+
options.each { |k, v| send("#{k}=", v) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
initializer "action_view_component.set_autoload_paths" do |app|
|
26
|
+
options = app.config.action_view_component
|
27
|
+
|
28
|
+
if options.show_previews && options.preview_path
|
29
|
+
ActiveSupport::Dependencies.autoload_paths << options.preview_path
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
initializer "action_view_component.eager_load_actions" do
|
34
|
+
ActiveSupport.on_load(:after_initialize) do
|
35
|
+
ActionView::Component::Base.descendants.each(&:compile)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
initializer "action_view_component.compile_config_methods" do
|
40
|
+
ActiveSupport.on_load(:action_view_component) do
|
41
|
+
config.compile_methods! if config.respond_to?(:compile_methods!)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
initializer "action_view_component.monkey_patch_render" do
|
46
|
+
ActiveSupport.on_load(:action_view) do
|
47
|
+
ActionView::Base.prepend ActionView::Component::RenderMonkeyPatch
|
48
|
+
end
|
49
|
+
|
50
|
+
ActiveSupport.on_load(:action_controller) do
|
51
|
+
ActionController::Base.prepend ActionView::Component::RenderingMonkeyPatch
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
config.after_initialize do |app|
|
56
|
+
options = app.config.action_view_component
|
57
|
+
|
58
|
+
if options.show_previews
|
59
|
+
app.routes.prepend do
|
60
|
+
get "/rails/components" => "rails/components#index", :internal => true
|
61
|
+
get "/rails/components/*path" => "rails/components#previews", :internal => true
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -1,65 +1,3 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
4
|
-
require "action_view/component"
|
5
|
-
|
6
|
-
module ActionView
|
7
|
-
module Component
|
8
|
-
class Railtie < Rails::Railtie # :nodoc:
|
9
|
-
config.action_view_component = ActiveSupport::OrderedOptions.new
|
10
|
-
|
11
|
-
initializer "action_view_component.set_configs" do |app|
|
12
|
-
options = app.config.action_view_component
|
13
|
-
|
14
|
-
options.show_previews = Rails.env.development? if options.show_previews.nil?
|
15
|
-
|
16
|
-
if options.show_previews
|
17
|
-
options.preview_path ||= defined?(Rails.root) ? "#{Rails.root}/test/components/previews" : nil
|
18
|
-
end
|
19
|
-
|
20
|
-
ActiveSupport.on_load(:action_view_component) do
|
21
|
-
options.each { |k, v| send("#{k}=", v) }
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
initializer "action_view_component.set_autoload_paths" do |app|
|
26
|
-
require "railties/lib/rails/components_controller"
|
27
|
-
|
28
|
-
options = app.config.action_view_component
|
29
|
-
|
30
|
-
if options.show_previews && options.preview_path
|
31
|
-
ActiveSupport::Dependencies.autoload_paths << options.preview_path
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
initializer "action_view_component.eager_load_actions" do
|
36
|
-
ActiveSupport.on_load(:after_initialize) do
|
37
|
-
ActionView::Component::Base.descendants.each(&:compile)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
initializer "action_view_component.compile_config_methods" do
|
42
|
-
ActiveSupport.on_load(:action_view_component) do
|
43
|
-
config.compile_methods! if config.respond_to?(:compile_methods!)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
initializer "action_view_component.monkey_patch_render" do
|
48
|
-
ActiveSupport.on_load(:action_view) do
|
49
|
-
ActionView::Base.prepend ActionView::Component::RenderMonkeyPatch
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
config.after_initialize do |app|
|
54
|
-
options = app.config.action_view_component
|
55
|
-
|
56
|
-
if options.show_previews
|
57
|
-
app.routes.prepend do
|
58
|
-
get "/rails/components" => "rails/components#index", :internal => true
|
59
|
-
get "/rails/components/*path" => "rails/components#previews", :internal => true
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
3
|
+
require "action_view/component/engine"
|
@@ -1,24 +1,29 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Monkey patch ActionView::Base#render to support ActionView::Component
|
4
|
-
#
|
5
|
-
# A version of this monkey patch was upstreamed in https://github.com/rails/rails/pull/36388
|
6
|
-
# We'll need to upstream an updated version of this eventually.
|
7
4
|
module ActionView
|
8
5
|
module Component
|
9
6
|
module RenderMonkeyPatch # :nodoc:
|
10
7
|
def render(options = {}, args = {}, &block)
|
11
8
|
if options.respond_to?(:render_in)
|
9
|
+
options.render_in(self, &block)
|
10
|
+
elsif options.is_a?(Class) && options < ActionView::Component::Base
|
12
11
|
ActiveSupport::Deprecation.warn(
|
13
|
-
"
|
12
|
+
"`render MyComponent, foo: :bar` has been deprecated and will be removed in v2.0.0. Use `render MyComponent.new(foo: :bar)` instead."
|
14
13
|
)
|
15
14
|
|
16
|
-
options.render_in(self, &block)
|
17
|
-
elsif options.is_a?(Class) && options < ActionView::Component::Base
|
18
15
|
options.new(args).render_in(self, &block)
|
19
16
|
elsif options.is_a?(Hash) && options.has_key?(:component)
|
17
|
+
ActiveSupport::Deprecation.warn(
|
18
|
+
"`render component: MyComponent, locals: { foo: :bar }` has been deprecated and will be removed in v2.0.0. Use `render MyComponent.new(foo: :bar)` instead."
|
19
|
+
)
|
20
|
+
|
20
21
|
options[:component].new(options[:locals]).render_in(self, &block)
|
21
22
|
elsif options.respond_to?(:to_component_class) && !options.to_component_class.nil?
|
23
|
+
ActiveSupport::Deprecation.warn(
|
24
|
+
"rendering objects that respond_to `to_component_class` has been deprecated and will be removed in v2.0.0. Use `render MyComponent.new(foo: :bar)` instead."
|
25
|
+
)
|
26
|
+
|
22
27
|
options.to_component_class.new(options).render_in(self, &block)
|
23
28
|
else
|
24
29
|
super
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionView
|
4
|
+
module Component
|
5
|
+
module RenderingMonkeyPatch # :nodoc:
|
6
|
+
def render(options = {}, args = {})
|
7
|
+
if options.respond_to?(:render_in)
|
8
|
+
self.response_body = options.render_in(self.view_context)
|
9
|
+
else
|
10
|
+
super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,10 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "capybara/minitest"
|
4
|
+
|
3
5
|
module ActionView
|
4
6
|
module Component
|
5
7
|
module TestHelpers
|
8
|
+
include Capybara::Minitest::Assertions
|
9
|
+
|
10
|
+
def page
|
11
|
+
Capybara::Node::Simple.new(@raw)
|
12
|
+
end
|
13
|
+
|
6
14
|
def render_inline(component, **args, &block)
|
7
|
-
|
15
|
+
@raw = controller.view_context.render(component, args, &block)
|
16
|
+
|
17
|
+
Nokogiri::HTML.fragment(@raw)
|
8
18
|
end
|
9
19
|
|
10
20
|
def controller
|
@@ -6,15 +6,18 @@ module Rails
|
|
6
6
|
source_root File.expand_path("templates", __dir__)
|
7
7
|
|
8
8
|
argument :attributes, type: :array, default: [], banner: "attribute"
|
9
|
-
hook_for :test_framework
|
10
9
|
check_class_collision suffix: "Component"
|
11
10
|
|
11
|
+
class_option :require_content, type: :boolean, default: false
|
12
|
+
|
12
13
|
def create_component_file
|
13
14
|
template "component.rb", File.join("app/components", class_path, "#{file_name}_component.rb")
|
14
15
|
end
|
15
16
|
|
16
|
-
|
17
|
-
|
17
|
+
hook_for :test_framework
|
18
|
+
|
19
|
+
hook_for :template_engine do |instance, template_engine|
|
20
|
+
instance.invoke template_engine, [instance.name], require_content: instance.send(:requires_content?)
|
18
21
|
end
|
19
22
|
|
20
23
|
private
|
@@ -24,6 +27,7 @@ module Rails
|
|
24
27
|
end
|
25
28
|
|
26
29
|
def requires_content?
|
30
|
+
return if behavior == :revoke
|
27
31
|
return @requires_content if @asked
|
28
32
|
|
29
33
|
@asked = true
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators/erb"
|
4
|
+
|
5
|
+
module Erb
|
6
|
+
module Generators
|
7
|
+
class ComponentGenerator < Base
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
9
|
+
|
10
|
+
class_option :require_content, type: :boolean, default: false
|
11
|
+
|
12
|
+
def copy_view_file
|
13
|
+
template "component.html.erb", File.join("app/components", class_path, "#{file_name}_component.html.erb")
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def requires_content?
|
19
|
+
options["require_content"]
|
20
|
+
end
|
21
|
+
|
22
|
+
def file_name
|
23
|
+
@_file_name ||= super.sub(/_component\z/i, "")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
File without changes
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators/erb/component_generator"
|
4
|
+
|
5
|
+
module Haml
|
6
|
+
module Generators
|
7
|
+
class ComponentGenerator < Erb::Generators::ComponentGenerator
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
9
|
+
|
10
|
+
class_option :require_content, type: :boolean, default: false
|
11
|
+
|
12
|
+
def copy_view_file
|
13
|
+
template "component.html.haml", File.join("app/components", class_path, "#{file_name}_component.html.haml")
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def requires_content?
|
19
|
+
options["require_content"]
|
20
|
+
end
|
21
|
+
|
22
|
+
def file_name
|
23
|
+
@_file_name ||= super.sub(/_component\z/i, "")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators/erb/component_generator"
|
4
|
+
|
5
|
+
module Slim
|
6
|
+
module Generators
|
7
|
+
class ComponentGenerator < Erb::Generators::ComponentGenerator
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
9
|
+
|
10
|
+
class_option :require_content, type: :boolean, default: false
|
11
|
+
|
12
|
+
def copy_view_file
|
13
|
+
template "component.html.slim", File.join("app/components", class_path, "#{file_name}_component.html.slim")
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def requires_content?
|
19
|
+
options["require_content"]
|
20
|
+
end
|
21
|
+
|
22
|
+
def file_name
|
23
|
+
@_file_name ||= super.sub(/_component\z/i, "")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: actionview-component
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.13.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GitHub Open Source
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-02
|
11
|
+
date: 2020-03-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: capybara
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -30,14 +44,14 @@ dependencies:
|
|
30
44
|
requirements:
|
31
45
|
- - "~>"
|
32
46
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
47
|
+
version: '13.0'
|
34
48
|
type: :development
|
35
49
|
prerelease: false
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
52
|
- - "~>"
|
39
53
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
54
|
+
version: '13.0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: minitest
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -143,27 +157,34 @@ files:
|
|
143
157
|
- README.md
|
144
158
|
- Rakefile
|
145
159
|
- actionview-component.gemspec
|
160
|
+
- app/controllers/rails/components_controller.rb
|
146
161
|
- lib/action_view/component.rb
|
147
162
|
- lib/action_view/component/base.rb
|
148
163
|
- lib/action_view/component/conversion.rb
|
164
|
+
- lib/action_view/component/engine.rb
|
149
165
|
- lib/action_view/component/preview.rb
|
150
166
|
- lib/action_view/component/previewable.rb
|
151
167
|
- lib/action_view/component/railtie.rb
|
152
168
|
- lib/action_view/component/render_monkey_patch.rb
|
169
|
+
- lib/action_view/component/rendering_monkey_patch.rb
|
153
170
|
- lib/action_view/component/template_error.rb
|
154
171
|
- lib/action_view/component/test_case.rb
|
155
172
|
- lib/action_view/component/test_helpers.rb
|
156
173
|
- lib/action_view/component/version.rb
|
157
174
|
- lib/rails/generators/component/USAGE
|
158
175
|
- lib/rails/generators/component/component_generator.rb
|
159
|
-
- lib/rails/generators/component/templates/component.html.erb.tt
|
160
176
|
- lib/rails/generators/component/templates/component.rb.tt
|
177
|
+
- lib/rails/generators/erb/component_generator.rb
|
178
|
+
- lib/rails/generators/erb/templates/component.html.erb.tt
|
179
|
+
- lib/rails/generators/haml/component_generator.rb
|
180
|
+
- lib/rails/generators/haml/templates/component.html.haml.tt
|
161
181
|
- lib/rails/generators/rspec/component_generator.rb
|
162
182
|
- lib/rails/generators/rspec/templates/component_spec.rb.tt
|
183
|
+
- lib/rails/generators/slim/component_generator.rb
|
184
|
+
- lib/rails/generators/slim/templates/component.html.slim
|
163
185
|
- lib/rails/generators/test_unit/component_generator.rb
|
164
186
|
- lib/rails/generators/test_unit/templates/component_test.rb.tt
|
165
187
|
- lib/railties/lib/rails.rb
|
166
|
-
- lib/railties/lib/rails/components_controller.rb
|
167
188
|
- lib/railties/lib/rails/templates/rails/components/index.html.erb
|
168
189
|
- lib/railties/lib/rails/templates/rails/components/preview.html.erb
|
169
190
|
- lib/railties/lib/rails/templates/rails/components/previews.html.erb
|