view_component 2.44.0 → 2.48.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/README.md +2 -1
- data/app/controllers/view_components_controller.rb +1 -2
- data/app/helpers/preview_helper.rb +52 -4
- data/app/views/view_components/_preview_source.html.erb +3 -3
- data/app/views/view_components/preview.html.erb +7 -3
- data/docs/CHANGELOG.md +219 -16
- data/lib/rails/generators/abstract_generator.rb +5 -1
- data/lib/rails/generators/component/component_generator.rb +3 -0
- data/lib/rails/generators/component/templates/component.rb.tt +1 -1
- data/lib/rails/generators/locale/component_generator.rb +46 -0
- data/lib/rails/generators/stimulus/component_generator.rb +1 -1
- data/lib/rails/generators/tailwindcss/component_generator.rb +11 -0
- data/lib/rails/generators/tailwindcss/templates/component.html.erb.tt +1 -0
- data/lib/view_component/base.rb +44 -12
- data/lib/view_component/collection.rb +20 -6
- data/lib/view_component/compile_cache.rb +5 -1
- data/lib/view_component/compiler.rb +85 -42
- data/lib/view_component/engine.rb +19 -1
- data/lib/view_component/preview.rb +1 -1
- data/lib/view_component/slot_v2.rb +4 -2
- data/lib/view_component/slotable.rb +4 -4
- data/lib/view_component/slotable_v2.rb +3 -3
- data/lib/view_component/test_helpers.rb +8 -2
- data/lib/view_component/version.rb +1 -1
- data/lib/view_component.rb +10 -1
- metadata +24 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3abce9e08dcb71614178ed68b9c8443211ff78790911057752d8fda6fbb194b7
|
4
|
+
data.tar.gz: 3ac0a8ff1d7cafd2eb12e04a24f1d8f3362675833e4fda780bc238b8fc5ed41f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dba31d0d37e73b7a1e26863d167f5d1eaefb8c5f53d9f542e47667090802b5f53b5c6b9c4b0a9188bf76f42d375c5d7a2cd3024065620aa9ff40b15911706cb8
|
7
|
+
data.tar.gz: f329872b25f36fe8fa0d018c2a5847ed0b6e47b095d16a27e89d2b0c7180f938d09730d0868405483a8e7c4fe4075afed56927a018b7a273ac4c94950d174fac
|
data/README.md
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+

|
2
|
+

|
2
3
|
|
3
4
|
A framework for building reusable, testable & encapsulated view components in Ruby on Rails.
|
4
5
|
|
@@ -29,12 +29,11 @@ class ViewComponentsController < Rails::ApplicationController # :nodoc:
|
|
29
29
|
@example_name = File.basename(params[:path])
|
30
30
|
@render_args = @preview.render_args(@example_name, params: params.permit!)
|
31
31
|
layout = determine_layout(@render_args[:layout], prepend_views: false)[:layout]
|
32
|
-
template = @render_args[:template]
|
33
32
|
locals = @render_args[:locals]
|
34
33
|
opts = {}
|
35
34
|
opts[:layout] = layout if layout.present? || layout == false
|
36
35
|
opts[:locals] = locals if locals.present?
|
37
|
-
render
|
36
|
+
render "view_components/preview", opts # rubocop:disable GitHub/RailsControllerRenderLiteral
|
38
37
|
end
|
39
38
|
end
|
40
39
|
|
@@ -4,16 +4,64 @@ module PreviewHelper
|
|
4
4
|
AVAILABLE_PRISM_LANGUAGES = ["ruby", "erb", "haml"]
|
5
5
|
FALLBACK_LANGUAGE = "ruby"
|
6
6
|
|
7
|
-
def
|
7
|
+
def preview_source
|
8
|
+
return if @render_args.nil?
|
9
|
+
|
10
|
+
render "preview_source" # rubocop:disable GitHub/RailsViewRenderPathsExist
|
11
|
+
end
|
12
|
+
|
13
|
+
def find_template_data(lookup_context:, template_identifier:)
|
14
|
+
template = lookup_context.find_template(template_identifier)
|
15
|
+
|
16
|
+
if Rails.version.to_f >= 6.1 || template.source.present?
|
17
|
+
return {
|
18
|
+
source: template.source,
|
19
|
+
prism_language_name: prism_language_name_by_template(template: template)
|
20
|
+
}
|
21
|
+
else
|
22
|
+
# Fetch template source via finding it through preview paths
|
23
|
+
# to accomodate source view when exclusively using templates
|
24
|
+
# for previews for Rails < 6.1.
|
25
|
+
all_template_paths = ViewComponent::Base.preview_paths.map do |preview_path|
|
26
|
+
Dir.glob("#{preview_path}/**/*")
|
27
|
+
end.flatten
|
28
|
+
|
29
|
+
# Search for templates the contain `html`.
|
30
|
+
matching_templates = all_template_paths.find_all do |template|
|
31
|
+
template =~ /#{template_identifier}*.(html)/
|
32
|
+
end
|
33
|
+
|
34
|
+
# In-case of a conflict due to multiple template files with
|
35
|
+
# the same name
|
36
|
+
raise "found 0 matches for templates for #{template_identifier}." if matching_templates.empty?
|
37
|
+
raise "found multiple templates for #{template_identifier}." if matching_templates.size > 1
|
38
|
+
|
39
|
+
template_file_path = matching_templates.first
|
40
|
+
template_source = File.read(template_file_path)
|
41
|
+
prism_language_name = prism_language_name_by_template_path(template_file_path: template_file_path)
|
42
|
+
|
43
|
+
return {
|
44
|
+
source: template_source,
|
45
|
+
prism_language_name: prism_language_name
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def prism_language_name_by_template(template:)
|
8
53
|
language = template.identifier.split(".").last
|
54
|
+
|
9
55
|
return FALLBACK_LANGUAGE unless AVAILABLE_PRISM_LANGUAGES.include? language
|
10
56
|
|
11
57
|
language
|
12
58
|
end
|
13
59
|
|
14
|
-
def
|
15
|
-
|
60
|
+
def prism_language_name_by_template_path(template_file_path:)
|
61
|
+
language = template_file_path.gsub(".html", "").split(".").last
|
16
62
|
|
17
|
-
|
63
|
+
return FALLBACK_LANGUAGE unless AVAILABLE_PRISM_LANGUAGES.include? language
|
64
|
+
|
65
|
+
language
|
18
66
|
end
|
19
67
|
end
|
@@ -7,9 +7,9 @@
|
|
7
7
|
<%= h @preview.preview_source(@example_name) %>
|
8
8
|
</code>
|
9
9
|
<% else %>
|
10
|
-
<%
|
11
|
-
<code class="language-<%= prism_language_name
|
12
|
-
<%= h
|
10
|
+
<% template_data = find_template_data(lookup_context: @view_renderer.lookup_context, template_identifier: @render_args[:template]) %>
|
11
|
+
<code class="language-<%= template_data[:prism_language_name] %>">
|
12
|
+
<%= h template_data[:source] %>
|
13
13
|
</code>
|
14
14
|
<% end %>
|
15
15
|
</pre>
|
@@ -1,7 +1,11 @@
|
|
1
|
-
<% if
|
2
|
-
|
1
|
+
<% if @render_args[:component] %>
|
2
|
+
<% if ViewComponent::Base.render_monkey_patch_enabled || Rails.version.to_f >= 6.1 %>
|
3
|
+
<%= render(@render_args[:component], @render_args[:args], &@render_args[:block]) %>
|
4
|
+
<% else %>
|
5
|
+
<%= render_component(@render_args[:component], &@render_args[:block]) %>
|
6
|
+
<% end %>
|
3
7
|
<% else %>
|
4
|
-
<%=
|
8
|
+
<%= render template: @render_args[:template], locals: @render_args[:locals] || {} %>
|
5
9
|
<% end %>
|
6
10
|
|
7
11
|
<% if ViewComponent::Base.show_previews_source %>
|
data/docs/CHANGELOG.md
CHANGED
@@ -7,6 +7,203 @@ title: Changelog
|
|
7
7
|
|
8
8
|
## main
|
9
9
|
|
10
|
+
## 2.48.0
|
11
|
+
|
12
|
+
* Correct path in example test command in Contributing docs.
|
13
|
+
|
14
|
+
*Mark Wilkinson*
|
15
|
+
|
16
|
+
* Update link to GOV.UK Components library in the resources list.
|
17
|
+
|
18
|
+
*Peter Yates*
|
19
|
+
|
20
|
+
* Add Lookbook to Resources docs page.
|
21
|
+
|
22
|
+
*Mark Perkins*
|
23
|
+
|
24
|
+
* Add blocking compiler mode for use in Rails development and testing modes, improving thread safety.
|
25
|
+
|
26
|
+
*Horia Radu*
|
27
|
+
|
28
|
+
* Add generators to support `tailwindcss-rails`.
|
29
|
+
|
30
|
+
*Dino Maric*, *Hans Lemuet*
|
31
|
+
|
32
|
+
* Add a namespaced component example to docs.
|
33
|
+
|
34
|
+
*Hans Lemuet*
|
35
|
+
|
36
|
+
* Setup `Appraisal` to add flexibility when testing ViewComponent against multiple Rails versions.
|
37
|
+
|
38
|
+
*Hans Lemuet*
|
39
|
+
|
40
|
+
* Return correct values for `request.path` and `request.query_string` methods when using the `with_request_url` test helper.
|
41
|
+
|
42
|
+
*Vasiliy Matyushin*
|
43
|
+
|
44
|
+
* Improve style in generators docs.
|
45
|
+
|
46
|
+
*Hans Lemuet*
|
47
|
+
|
48
|
+
* Correctly type Ruby version strings and update Rails versions used in CI configuration.
|
49
|
+
|
50
|
+
*Hans Lemuet*
|
51
|
+
|
52
|
+
* Make `ViewComponent::Collection` act like a collection of view components.
|
53
|
+
|
54
|
+
*Sammy Henningsson*
|
55
|
+
|
56
|
+
* Update `@param` of `#render_inline` to include `ViewComponent::Collection`.
|
57
|
+
|
58
|
+
*Yutaka Kamei*
|
59
|
+
|
60
|
+
* Add Wecasa to users list.
|
61
|
+
|
62
|
+
*Mohamed Ziata*
|
63
|
+
|
64
|
+
## 2.47.0
|
65
|
+
|
66
|
+
* Display preview source on previews that exclusively use templates.
|
67
|
+
|
68
|
+
*Edwin Mak*
|
69
|
+
|
70
|
+
* Add a test to ensure trailing newlines are stripped when rendering with `#render_in`.
|
71
|
+
|
72
|
+
*Simon Fish*
|
73
|
+
|
74
|
+
* Add WEBrick as a depenency to the application.
|
75
|
+
|
76
|
+
*Connor McQuillan*
|
77
|
+
|
78
|
+
* Update Ruby version in `.tool-versions`.
|
79
|
+
|
80
|
+
*Connor McQuillan*
|
81
|
+
|
82
|
+
* Add a test to ensure blocks can be passed into lambda slots without the need for any other arguments.
|
83
|
+
|
84
|
+
*Simon Fish*
|
85
|
+
|
86
|
+
* Add linters for file consistency.
|
87
|
+
|
88
|
+
*Simon Fish*
|
89
|
+
|
90
|
+
* Add @boardfish to docs/index.md and sort contributors.
|
91
|
+
|
92
|
+
*Simon Fish*
|
93
|
+
|
94
|
+
* Set up Codespaces for bug replication.
|
95
|
+
|
96
|
+
*Simon Fish*
|
97
|
+
|
98
|
+
* Add instructions for replicating bugs and failures.
|
99
|
+
|
100
|
+
*Simon Fish*
|
101
|
+
|
102
|
+
* Make @boardfish a committer.
|
103
|
+
|
104
|
+
*Joel Hawksley*
|
105
|
+
|
106
|
+
* Validate collection parameter with Active Model attribute names.
|
107
|
+
|
108
|
+
*Simon Fish*
|
109
|
+
|
110
|
+
* Fix `helpers` not working with component slots when rendered more than 2 component levels deep.
|
111
|
+
|
112
|
+
*Blake Williams*
|
113
|
+
|
114
|
+
* Update ruby to the latest versions
|
115
|
+
|
116
|
+
*Pedro Paiva*
|
117
|
+
|
118
|
+
* Fix `vale` linter config options.
|
119
|
+
|
120
|
+
*Hans Lemuet*
|
121
|
+
|
122
|
+
* Improve Contributing docs to include how to run tests for a specific version on Rails.
|
123
|
+
|
124
|
+
*Hans Lemuet*
|
125
|
+
|
126
|
+
* Add failing test for default form builder and documentation around known issue.
|
127
|
+
|
128
|
+
*Simon Fish*
|
129
|
+
|
130
|
+
* Add `--locale` flag to the component generator. Generates as many locale files as defined in `I18n.available_locales`, alongside the component.
|
131
|
+
* Add config option `config.view_component.generate_locale` to enable project-wide locale generation.
|
132
|
+
* Add config option `config.view_component.generate_distinct_locale_files` to enable project-wide per-locale translations file generation.
|
133
|
+
|
134
|
+
*Bob Maerten*
|
135
|
+
|
136
|
+
* Add config option `config.view_component.generate_sidecar` to always generate in the sidecar directory.
|
137
|
+
|
138
|
+
*Gleydson Tavares*
|
139
|
+
|
140
|
+
## 2.46.0
|
141
|
+
|
142
|
+
* Add thread safety to the compiler.
|
143
|
+
|
144
|
+
*Horia Radu*
|
145
|
+
|
146
|
+
* Add theme-specific logo images to readme.
|
147
|
+
|
148
|
+
*Dylan Smith*
|
149
|
+
|
150
|
+
* Add Orbit to users list.
|
151
|
+
|
152
|
+
*Nicolas Goutay*
|
153
|
+
|
154
|
+
* Increase clarity around purpose and use of slots.
|
155
|
+
|
156
|
+
*Simon Fish*
|
157
|
+
|
158
|
+
* Deprecate loading `view_component/engine` directly.
|
159
|
+
|
160
|
+
**Upgrade notice**: You should update your `Gemfile` like this:
|
161
|
+
|
162
|
+
```diff
|
163
|
+
- gem "view_component", require: "view_component/engine"`
|
164
|
+
+ gem "view_component"
|
165
|
+
```
|
166
|
+
|
167
|
+
*Yoshiyuki Hirano*
|
168
|
+
|
169
|
+
## 2.45.0
|
170
|
+
|
171
|
+
* Remove internal APIs from API documentation, fix link to license.
|
172
|
+
|
173
|
+
*Joel Hawksley*
|
174
|
+
|
175
|
+
* Add @yhirano55 to triage team.
|
176
|
+
|
177
|
+
*Joel Hawksley*
|
178
|
+
|
179
|
+
* Correct a typo in the sample slots code.
|
180
|
+
|
181
|
+
*Simon Fish*
|
182
|
+
|
183
|
+
* Add note about `allowed_queries`.
|
184
|
+
|
185
|
+
*Joel Hawksley*
|
186
|
+
|
187
|
+
* Add `vale` content linter.
|
188
|
+
|
189
|
+
*Joel Hawksley*
|
190
|
+
|
191
|
+
* Remove `require "rails/generators/test_case"` in generator tests.
|
192
|
+
|
193
|
+
*Yoshiyuki Hirano*
|
194
|
+
|
195
|
+
* Suppress zeitwerk warning about circular require.
|
196
|
+
|
197
|
+
*Yoshiyuki Hirano*
|
198
|
+
|
199
|
+
* Move `test_unit_generator_test.rb` from `test/view_component/` to `test/generators/`.
|
200
|
+
|
201
|
+
*Yoshiyuki Hirano*
|
202
|
+
|
203
|
+
* Unify test code of `TestUnitGeneratorTest` with the other generators tests.
|
204
|
+
|
205
|
+
*Yoshiyuki Hirano*
|
206
|
+
|
10
207
|
## 2.44.0
|
11
208
|
|
12
209
|
* Rename internal accessor to use private naming.
|
@@ -142,7 +339,7 @@ title: Changelog
|
|
142
339
|
|
143
340
|
*Matthew Rider*
|
144
341
|
|
145
|
-
* Fix bug where `with_collection_parameter`
|
342
|
+
* Fix bug where `with_collection_parameter` didn't inherit from parent component.
|
146
343
|
|
147
344
|
*Will Drexler*, *Christian Campoli*
|
148
345
|
|
@@ -346,7 +543,7 @@ title: Changelog
|
|
346
543
|
|
347
544
|
*Hans Lemuet*
|
348
545
|
|
349
|
-
* Fix bug where ViewComponents
|
546
|
+
* Fix bug where ViewComponents didn't work in ActionMailers.
|
350
547
|
|
351
548
|
*dark-panda*
|
352
549
|
|
@@ -394,7 +591,7 @@ title: Changelog
|
|
394
591
|
|
395
592
|
## 2.31.0
|
396
593
|
|
397
|
-
_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
|
594
|
+
_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 shouldn't be returned. (`<%`)_
|
398
595
|
|
399
596
|
* Add `#with_content` to allow setting content without a block.
|
400
597
|
|
@@ -405,7 +602,7 @@ _Note: This release includes an underlying change to Slots that may affect incor
|
|
405
602
|
*Mario Schüttel*
|
406
603
|
|
407
604
|
* Improve feature parity with Rails translations
|
408
|
-
* Don't create a translation
|
605
|
+
* Don't create a translation back end if the component has no translation file
|
409
606
|
* Mark translation keys ending with `html` as HTML-safe
|
410
607
|
* Always convert keys to String
|
411
608
|
* Support multiple keys
|
@@ -447,7 +644,7 @@ _Note: This release includes an underlying change to Slots that may affect incor
|
|
447
644
|
|
448
645
|
*Alex Robbin, Blake Williams*
|
449
646
|
|
450
|
-
* Experimental: call `._sidecar_files` to fetch the sidecar files for a given list of extensions,
|
647
|
+
* Experimental: call `._sidecar_files` to fetch the sidecar files for a given list of extensions, for example passing `["yml", "yaml"]`.
|
451
648
|
|
452
649
|
*Elia Schito*
|
453
650
|
|
@@ -487,11 +684,11 @@ _Note: This release includes an underlying change to Slots that may affect incor
|
|
487
684
|
|
488
685
|
## 2.26.0
|
489
686
|
|
490
|
-
*
|
687
|
+
* Delay evaluating component `content` in `render?`, preventing the `content` block from being evaluated when `render?` returns false.
|
491
688
|
|
492
689
|
*Blake Williams*
|
493
690
|
|
494
|
-
*
|
691
|
+
* Don't generate template when using `--inline` flag.
|
495
692
|
|
496
693
|
*Hans Lemuet*
|
497
694
|
|
@@ -552,7 +749,7 @@ _Note: This release includes an underlying change to Slots that may affect incor
|
|
552
749
|
* `with_slot collection: true` becomes `renders_many`.
|
553
750
|
* Slot definitions now accept either a component class, component class name, or a lambda instead of a `class_name:` keyword argument.
|
554
751
|
* Slots now support positional arguments.
|
555
|
-
* Slots no longer use the `content` attribute to render content, instead relying on `to_s`.
|
752
|
+
* Slots no longer use the `content` attribute to render content, instead relying on `to_s`. for example `<%= my_slot %>`.
|
556
753
|
* Slot values are no longer set via the `slot` method, and instead use the name of the slot.
|
557
754
|
|
558
755
|
*Blake Williams*
|
@@ -615,7 +812,7 @@ _Note: This release includes an underlying change to Slots that may affect incor
|
|
615
812
|
|
616
813
|
## 2.18.2
|
617
814
|
|
618
|
-
* Raise an error if controller or view context is accessed during initialize as they
|
815
|
+
* Raise an error if controller or view context is accessed during initialize as they're only available in render.
|
619
816
|
|
620
817
|
*Julian Nadeau*
|
621
818
|
|
@@ -631,7 +828,7 @@ _Note: This release includes an underlying change to Slots that may affect incor
|
|
631
828
|
|
632
829
|
## 2.18.0
|
633
830
|
|
634
|
-
* Fix auto
|
831
|
+
* Fix auto loading of previews (changes no longer require a server restart)
|
635
832
|
|
636
833
|
*Matt Brictson*
|
637
834
|
|
@@ -724,7 +921,7 @@ _Note: This release includes an underlying change to Slots that may affect incor
|
|
724
921
|
|
725
922
|
## 2.10.0
|
726
923
|
|
727
|
-
* Raise an `ArgumentError` with a helpful message when Ruby
|
924
|
+
* Raise an `ArgumentError` with a helpful message when Ruby can't parse a component class.
|
728
925
|
|
729
926
|
*Max Beizer*
|
730
927
|
|
@@ -816,7 +1013,7 @@ _Note: This release includes an underlying change to Slots that may affect incor
|
|
816
1013
|
|
817
1014
|
## v2.2.1
|
818
1015
|
|
819
|
-
* Fix bug where template
|
1016
|
+
* Fix bug where template couldn't be found if `inherited` was redefined.
|
820
1017
|
|
821
1018
|
*Joel Hawksley*
|
822
1019
|
|
@@ -832,7 +1029,7 @@ _Note: This release includes an underlying change to Slots that may affect incor
|
|
832
1029
|
|
833
1030
|
## v2.1.0
|
834
1031
|
|
835
|
-
* Support rendering collections (
|
1032
|
+
* Support rendering collections (for example, `render(MyComponent.with_collection(@items))`).
|
836
1033
|
|
837
1034
|
*Tim Clem*
|
838
1035
|
|
@@ -854,7 +1051,7 @@ _Note: This release includes an underlying change to Slots that may affect incor
|
|
854
1051
|
|
855
1052
|
*Andrew Mason*
|
856
1053
|
|
857
|
-
* ViewComponent generators
|
1054
|
+
* ViewComponent generators don't not prompt for content requirement.
|
858
1055
|
|
859
1056
|
*Joel Hawksley*
|
860
1057
|
|
@@ -976,7 +1173,7 @@ _Note: This release includes an underlying change to Slots that may affect incor
|
|
976
1173
|
|
977
1174
|
*Jon Palmer*
|
978
1175
|
|
979
|
-
* Add `#render?` hook to
|
1176
|
+
* Add `#render?` hook to allow components to be no-ops.
|
980
1177
|
|
981
1178
|
*Kyle Fox*
|
982
1179
|
|
@@ -1044,7 +1241,9 @@ _Note: This release includes an underlying change to Slots that may affect incor
|
|
1044
1241
|
|
1045
1242
|
* Fix edge case issue with extracting variants from less conventional source_locations.
|
1046
1243
|
|
1244
|
+
<!-- vale proselint.GenderBias = NO -->
|
1047
1245
|
*Ryan Workman*
|
1246
|
+
<!-- vale proselint.GenderBias = YES -->
|
1048
1247
|
|
1049
1248
|
## v1.6.0
|
1050
1249
|
|
@@ -1080,7 +1279,9 @@ _Note: This release includes an underlying change to Slots that may affect incor
|
|
1080
1279
|
|
1081
1280
|
* Add support for RSpec to generators.
|
1082
1281
|
|
1282
|
+
<!-- vale proselint.GenderBias = NO -->
|
1083
1283
|
*Dylan Clark, Ryan Workman*
|
1284
|
+
<!-- vale proselint.GenderBias = YES -->
|
1084
1285
|
|
1085
1286
|
* Require controllers as part of setting autoload paths.
|
1086
1287
|
|
@@ -1104,7 +1305,9 @@ Note: `actionview-component` is now loaded by requiring `actionview/component`,
|
|
1104
1305
|
|
1105
1306
|
* Fix issue with generating component method signatures.
|
1106
1307
|
|
1308
|
+
<!-- vale proselint.GenderBias = NO -->
|
1107
1309
|
*Ryan Workman, Dylan Clark*
|
1310
|
+
<!-- vale proselint.GenderBias = YES -->
|
1108
1311
|
|
1109
1312
|
* Create component generator.
|
1110
1313
|
|
@@ -1176,7 +1379,7 @@ Note: `actionview-component` is now loaded by requiring `actionview/component`,
|
|
1176
1379
|
|
1177
1380
|
## v1.3.3
|
1178
1381
|
|
1179
|
-
*
|
1382
|
+
* Don't raise error when sidecar files that aren't templates exist.
|
1180
1383
|
|
1181
1384
|
*Joel Hawksley*
|
1182
1385
|
|
@@ -15,7 +15,7 @@ module ViewComponent
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def destination_directory
|
18
|
-
if
|
18
|
+
if sidecar?
|
19
19
|
File.join(component_path, class_path, destination_file_name)
|
20
20
|
else
|
21
21
|
File.join(component_path, class_path)
|
@@ -42,5 +42,9 @@ module ViewComponent
|
|
42
42
|
gsub("/", "--")
|
43
43
|
end
|
44
44
|
end
|
45
|
+
|
46
|
+
def sidecar?
|
47
|
+
options["sidecar"] || ViewComponent::Base.generate_sidecar
|
48
|
+
end
|
45
49
|
end
|
46
50
|
end
|
@@ -15,6 +15,7 @@ module Rails
|
|
15
15
|
class_option :parent, type: :string, desc: "The parent class for the generated component"
|
16
16
|
class_option :stimulus, type: :boolean, default: ViewComponent::Base.generate_stimulus_controller
|
17
17
|
class_option :sidecar, type: :boolean, default: false
|
18
|
+
class_option :locale, type: :boolean, default: ViewComponent::Base.generate_locale
|
18
19
|
|
19
20
|
def create_component_file
|
20
21
|
template "component.rb", File.join(component_path, class_path, "#{file_name}_component.rb")
|
@@ -26,6 +27,8 @@ module Rails
|
|
26
27
|
|
27
28
|
hook_for :stimulus, type: :boolean
|
28
29
|
|
30
|
+
hook_for :locale, type: :boolean
|
31
|
+
|
29
32
|
hook_for :template_engine do |instance, template_engine|
|
30
33
|
instance.invoke template_engine, [instance.name]
|
31
34
|
end
|
@@ -6,7 +6,7 @@ class <%= class_name %>Component < <%= parent_class %>
|
|
6
6
|
<%= initialize_body %>
|
7
7
|
end
|
8
8
|
<%- end -%>
|
9
|
-
<%- if initialize_call_method_for_inline? -%>
|
9
|
+
<%- if initialize_call_method_for_inline? -%>
|
10
10
|
def call
|
11
11
|
content_tag :h1, "Hello world!"<%= ", data: { controller: \"#{stimulus_controller}\" }" if options["stimulus"] %>
|
12
12
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators/abstract_generator"
|
4
|
+
|
5
|
+
module Locale
|
6
|
+
module Generators
|
7
|
+
class ComponentGenerator < ::Rails::Generators::NamedBase
|
8
|
+
include ViewComponent::AbstractGenerator
|
9
|
+
|
10
|
+
source_root File.expand_path("templates", __dir__)
|
11
|
+
argument :attributes, type: :array, default: [], banner: "attribute"
|
12
|
+
class_option :sidecar, type: :boolean, default: false
|
13
|
+
|
14
|
+
def create_locale_file
|
15
|
+
if ViewComponent::Base.generate_distinct_locale_files
|
16
|
+
I18n.available_locales.each do |locale|
|
17
|
+
create_file destination(locale), translations_hash([locale]).to_yaml
|
18
|
+
end
|
19
|
+
else
|
20
|
+
create_file destination, translations_hash(I18n.available_locales).to_yaml
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def translations_hash(locales = [:en])
|
27
|
+
locales.map { |locale| [locale.to_s, translation_keys] }.to_h
|
28
|
+
end
|
29
|
+
|
30
|
+
def translation_keys
|
31
|
+
keys = attributes.map(&:name)
|
32
|
+
keys = %w[hello] if keys.empty?
|
33
|
+
keys.map { |name| [name, name.capitalize] }.to_h
|
34
|
+
end
|
35
|
+
|
36
|
+
def destination(locale = nil)
|
37
|
+
extention = ".#{locale}" if locale
|
38
|
+
if sidecar?
|
39
|
+
File.join(component_path, class_path, "#{file_name}_component", "#{file_name}_component#{extention}.yml")
|
40
|
+
else
|
41
|
+
File.join(component_path, class_path, "#{file_name}_component#{extention}.yml")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -23,7 +23,7 @@ module Stimulus
|
|
23
23
|
private
|
24
24
|
|
25
25
|
def destination
|
26
|
-
if
|
26
|
+
if sidecar?
|
27
27
|
File.join(component_path, class_path, "#{file_name}_component", "#{file_name}_component_controller.js")
|
28
28
|
else
|
29
29
|
File.join(component_path, class_path, "#{file_name}_component_controller.js")
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators/erb/component_generator"
|
4
|
+
|
5
|
+
module Tailwindcss
|
6
|
+
module Generators
|
7
|
+
class ComponentGenerator < Erb::Generators::ComponentGenerator
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<div<%= data_attributes %>>Add <%= class_name %> template here</div>
|
data/lib/view_component/base.rb
CHANGED
@@ -152,7 +152,7 @@ module ViewComponent
|
|
152
152
|
if view_context.nil?
|
153
153
|
raise(
|
154
154
|
ViewContextCalledBeforeRenderError,
|
155
|
-
"`#controller`
|
155
|
+
"`#controller` can't be used during initialization, as it depends " \
|
156
156
|
"on the view context that only exists once a ViewComponent is passed to " \
|
157
157
|
"the Rails render pipeline.\n\n" \
|
158
158
|
"It's sometimes possible to fix this issue by moving code dependent on " \
|
@@ -171,7 +171,7 @@ module ViewComponent
|
|
171
171
|
if view_context.nil?
|
172
172
|
raise(
|
173
173
|
ViewContextCalledBeforeRenderError,
|
174
|
-
"`#helpers`
|
174
|
+
"`#helpers` can't be used during initialization, as it depends " \
|
175
175
|
"on the view context that only exists once a ViewComponent is passed to " \
|
176
176
|
"the Rails render pipeline.\n\n" \
|
177
177
|
"It's sometimes possible to fix this issue by moving code dependent on " \
|
@@ -206,7 +206,7 @@ module ViewComponent
|
|
206
206
|
#
|
207
207
|
# @private
|
208
208
|
def format
|
209
|
-
# Ruby 2.6 throws a warning without checking `defined?`, 2.7
|
209
|
+
# Ruby 2.6 throws a warning without checking `defined?`, 2.7 doesn't
|
210
210
|
if defined?(@__vc_variant)
|
211
211
|
@__vc_variant
|
212
212
|
end
|
@@ -279,11 +279,31 @@ module ViewComponent
|
|
279
279
|
#
|
280
280
|
mattr_accessor :generate_stimulus_controller, instance_writer: false, default: false
|
281
281
|
|
282
|
+
# Always generate translations file alongside the component:
|
283
|
+
#
|
284
|
+
# config.view_component.generate_locale = true
|
285
|
+
#
|
286
|
+
# Defaults to `false`.
|
287
|
+
#
|
288
|
+
mattr_accessor :generate_locale, instance_writer: false, default: false
|
289
|
+
|
290
|
+
# Always generate as many translations files as available locales:
|
291
|
+
#
|
292
|
+
# config.view_component.generate_distinct_locale_files = true
|
293
|
+
#
|
294
|
+
# Defaults to `false`.
|
295
|
+
#
|
296
|
+
# One file will be generated for each configured `I18n.available_locales`.
|
297
|
+
# Fallback on `[:en]` when no available_locales is defined.
|
298
|
+
#
|
299
|
+
mattr_accessor :generate_distinct_locale_files, instance_writer: false, default: false
|
300
|
+
|
282
301
|
# Path for component files
|
283
302
|
#
|
284
303
|
# config.view_component.view_component_path = "app/my_components"
|
285
304
|
#
|
286
|
-
# Defaults to
|
305
|
+
# Defaults to `app/components`.
|
306
|
+
#
|
287
307
|
mattr_accessor :view_component_path, instance_writer: false, default: "app/components"
|
288
308
|
|
289
309
|
# Parent class for generated components
|
@@ -291,8 +311,16 @@ module ViewComponent
|
|
291
311
|
# config.view_component.component_parent_class = "MyBaseComponent"
|
292
312
|
#
|
293
313
|
# Defaults to "ApplicationComponent" if defined, "ViewComponent::Base" otherwise.
|
294
|
-
|
295
|
-
|
314
|
+
#
|
315
|
+
mattr_accessor :component_parent_class, instance_writer: false
|
316
|
+
|
317
|
+
# Always generate a component with a sidecar directory:
|
318
|
+
#
|
319
|
+
# config.view_component.generate_sidecar = true
|
320
|
+
#
|
321
|
+
# Defaults to `false`.
|
322
|
+
#
|
323
|
+
mattr_accessor :generate_sidecar, instance_writer: false, default: false
|
296
324
|
|
297
325
|
class << self
|
298
326
|
# @private
|
@@ -318,7 +346,7 @@ module ViewComponent
|
|
318
346
|
|
319
347
|
# Add support for nested components defined in the same file.
|
320
348
|
#
|
321
|
-
#
|
349
|
+
# for example
|
322
350
|
#
|
323
351
|
# class MyComponent < ViewComponent::Base
|
324
352
|
# class MyOtherComponent < ViewComponent::Base
|
@@ -431,7 +459,7 @@ module ViewComponent
|
|
431
459
|
end
|
432
460
|
|
433
461
|
# Ensure the component initializer accepts the
|
434
|
-
# collection parameter. By default, we
|
462
|
+
# collection parameter. By default, we don't
|
435
463
|
# validate that the default parameter name
|
436
464
|
# is accepted, as support for collection
|
437
465
|
# rendering is optional.
|
@@ -442,7 +470,7 @@ module ViewComponent
|
|
442
470
|
return unless parameter
|
443
471
|
return if initialize_parameter_names.include?(parameter)
|
444
472
|
|
445
|
-
# If Ruby
|
473
|
+
# If Ruby can't parse the component class, then the initalize
|
446
474
|
# parameters will be empty and ViewComponent will not be able to render
|
447
475
|
# the component.
|
448
476
|
if initialize_parameters.empty?
|
@@ -455,14 +483,14 @@ module ViewComponent
|
|
455
483
|
end
|
456
484
|
|
457
485
|
raise ArgumentError.new(
|
458
|
-
"The initializer for #{self}
|
486
|
+
"The initializer for #{self} doesn't accept the parameter `#{parameter}`, " \
|
459
487
|
"which is required in order to render it as a collection.\n\n" \
|
460
488
|
"To fix this issue, update the initializer to accept `#{parameter}`.\n\n" \
|
461
489
|
"See https://viewcomponent.org/guide/collections.html for more information on rendering collections."
|
462
490
|
)
|
463
491
|
end
|
464
492
|
|
465
|
-
# Ensure the component initializer
|
493
|
+
# Ensure the component initializer doesn't define
|
466
494
|
# invalid parameters that could override the framework's
|
467
495
|
# methods.
|
468
496
|
# @private TODO: add documentation
|
@@ -470,7 +498,7 @@ module ViewComponent
|
|
470
498
|
return unless initialize_parameter_names.include?(RESERVED_PARAMETER)
|
471
499
|
|
472
500
|
raise ViewComponent::ComponentError.new(
|
473
|
-
"#{self} initializer
|
501
|
+
"#{self} initializer can't accept the parameter `#{RESERVED_PARAMETER}`, as it will override a " \
|
474
502
|
"public ViewComponent method. To fix this issue, rename the parameter."
|
475
503
|
)
|
476
504
|
end
|
@@ -507,6 +535,10 @@ module ViewComponent
|
|
507
535
|
private
|
508
536
|
|
509
537
|
def initialize_parameter_names
|
538
|
+
return attribute_names.map(&:to_sym) if respond_to?(:attribute_names)
|
539
|
+
|
540
|
+
return attribute_types.keys.map(&:to_sym) if Rails::VERSION::MAJOR <= 5 && respond_to?(:attribute_types)
|
541
|
+
|
510
542
|
initialize_parameters.map(&:last)
|
511
543
|
end
|
512
544
|
|
@@ -4,20 +4,34 @@ require "action_view/renderer/collection_renderer" if Rails.version.to_f >= 6.1
|
|
4
4
|
|
5
5
|
module ViewComponent
|
6
6
|
class Collection
|
7
|
+
include Enumerable
|
7
8
|
attr_reader :component
|
8
9
|
|
9
10
|
delegate :format, to: :component
|
11
|
+
delegate :size, to: :@collection
|
10
12
|
|
11
13
|
def render_in(view_context, &block)
|
14
|
+
components.map do |component|
|
15
|
+
component.render_in(view_context, &block)
|
16
|
+
end.join.html_safe # rubocop:disable Rails/OutputSafety
|
17
|
+
end
|
18
|
+
|
19
|
+
def components
|
20
|
+
return @components if defined? @components
|
21
|
+
|
12
22
|
iterator = ActionView::PartialIteration.new(@collection.size)
|
13
23
|
|
14
24
|
component.validate_collection_parameter!(validate_default: true)
|
15
25
|
|
16
|
-
@collection.map do |item|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
end
|
26
|
+
@components = @collection.map do |item|
|
27
|
+
component.new(**component_options(item, iterator)).tap do |component|
|
28
|
+
iterator.iterate!
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def each(&block)
|
34
|
+
components.each(&block)
|
21
35
|
end
|
22
36
|
|
23
37
|
private
|
@@ -42,7 +56,7 @@ module ViewComponent
|
|
42
56
|
def component_options(item, iterator)
|
43
57
|
item_options = { component.collection_parameter => item }
|
44
58
|
item_options[component.collection_counter_parameter] = iterator.index + 1 if component.counter_argument_present?
|
45
|
-
item_options[component.collection_iteration_parameter] = iterator if component.iteration_argument_present?
|
59
|
+
item_options[component.collection_iteration_parameter] = iterator.dup if component.iteration_argument_present?
|
46
60
|
|
47
61
|
@options.merge(item_options)
|
48
62
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module ViewComponent
|
4
4
|
# Keeps track of which templates have already been compiled
|
5
|
-
# This
|
5
|
+
# This isn't part of the public API
|
6
6
|
module CompileCache
|
7
7
|
mattr_accessor :cache, instance_reader: false, instance_accessor: false do
|
8
8
|
Set.new
|
@@ -18,6 +18,10 @@ module ViewComponent
|
|
18
18
|
cache.include? klass
|
19
19
|
end
|
20
20
|
|
21
|
+
def invalidate_class!(klass)
|
22
|
+
cache.delete(klass)
|
23
|
+
end
|
24
|
+
|
21
25
|
def invalidate!
|
22
26
|
cache.clear
|
23
27
|
end
|
@@ -2,66 +2,95 @@
|
|
2
2
|
|
3
3
|
module ViewComponent
|
4
4
|
class Compiler
|
5
|
+
# Lock required to be obtained before compiling the component
|
6
|
+
attr_reader :__vc_compiler_lock
|
7
|
+
|
8
|
+
# Compiler mode. Can be either:
|
9
|
+
# * development (a blocking mode which ensures thread safety when redefining the `call` method for components,
|
10
|
+
# default in Rails development and test mode)
|
11
|
+
# * production (a non-blocking mode, default in Rails production mode)
|
12
|
+
DEVELOPMENT_MODE = :development
|
13
|
+
PRODUCTION_MODE = :production
|
14
|
+
|
15
|
+
class_attribute :mode, default: PRODUCTION_MODE
|
16
|
+
|
5
17
|
def initialize(component_class)
|
6
18
|
@component_class = component_class
|
19
|
+
@__vc_compiler_lock = Monitor.new
|
7
20
|
end
|
8
21
|
|
9
22
|
def compiled?
|
10
23
|
CompileCache.compiled?(component_class)
|
11
24
|
end
|
12
25
|
|
26
|
+
def development?
|
27
|
+
self.class.mode == DEVELOPMENT_MODE
|
28
|
+
end
|
29
|
+
|
13
30
|
def compile(raise_errors: false)
|
14
31
|
return if compiled?
|
15
32
|
|
16
|
-
|
33
|
+
with_lock do
|
34
|
+
CompileCache.invalidate_class!(component_class)
|
17
35
|
|
18
|
-
|
19
|
-
raise ViewComponent::ComponentError.new(
|
20
|
-
"#{component_class} implements a reserved method, `#with_content`.\n\n" \
|
21
|
-
"To fix this issue, change the name of the method."
|
22
|
-
)
|
23
|
-
end
|
24
|
-
|
25
|
-
if template_errors.present?
|
26
|
-
raise ViewComponent::TemplateError.new(template_errors) if raise_errors
|
36
|
+
subclass_instance_methods = component_class.instance_methods(false)
|
27
37
|
|
28
|
-
|
29
|
-
|
38
|
+
if subclass_instance_methods.include?(:with_content) && raise_errors
|
39
|
+
raise ViewComponent::ComponentError.new(
|
40
|
+
"#{component_class} implements a reserved method, `#with_content`.\n\n" \
|
41
|
+
"To fix this issue, change the name of the method."
|
42
|
+
)
|
43
|
+
end
|
30
44
|
|
31
|
-
|
32
|
-
|
33
|
-
"`#before_render_check` will be removed in v3.0.0.\n\n" \
|
34
|
-
"To fix this issue, use `#before_render` instead."
|
35
|
-
)
|
36
|
-
end
|
45
|
+
if template_errors.present?
|
46
|
+
raise ViewComponent::TemplateError.new(template_errors) if raise_errors
|
37
47
|
|
38
|
-
|
39
|
-
|
40
|
-
component_class.validate_collection_parameter!
|
41
|
-
end
|
48
|
+
return false
|
49
|
+
end
|
42
50
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
51
|
+
if subclass_instance_methods.include?(:before_render_check)
|
52
|
+
ActiveSupport::Deprecation.warn(
|
53
|
+
"`#before_render_check` will be removed in v3.0.0.\n\n" \
|
54
|
+
"To fix this issue, use `#before_render` instead."
|
55
|
+
)
|
56
|
+
end
|
47
57
|
|
48
|
-
if
|
49
|
-
component_class.
|
58
|
+
if raise_errors
|
59
|
+
component_class.validate_initialization_parameters!
|
60
|
+
component_class.validate_collection_parameter!
|
50
61
|
end
|
51
62
|
|
52
|
-
|
63
|
+
templates.each do |template|
|
64
|
+
# Remove existing compiled template methods,
|
65
|
+
# as Ruby warns when redefining a method.
|
66
|
+
method_name = call_method_name(template[:variant])
|
67
|
+
|
68
|
+
if component_class.instance_methods.include?(method_name.to_sym)
|
69
|
+
component_class.send(:undef_method, method_name.to_sym)
|
70
|
+
end
|
71
|
+
|
72
|
+
component_class.class_eval <<-RUBY, template[:path], -1
|
53
73
|
def #{method_name}
|
54
74
|
@output_buffer = ActionView::OutputBuffer.new
|
55
75
|
#{compiled_template(template[:path])}
|
56
76
|
end
|
57
|
-
|
58
|
-
|
77
|
+
RUBY
|
78
|
+
end
|
79
|
+
|
80
|
+
define_render_template_for
|
59
81
|
|
60
|
-
|
82
|
+
component_class._after_compile
|
61
83
|
|
62
|
-
|
84
|
+
CompileCache.register(component_class)
|
85
|
+
end
|
86
|
+
end
|
63
87
|
|
64
|
-
|
88
|
+
def with_lock(&block)
|
89
|
+
if development?
|
90
|
+
__vc_compiler_lock.synchronize(&block)
|
91
|
+
else
|
92
|
+
block.call
|
93
|
+
end
|
65
94
|
end
|
66
95
|
|
67
96
|
private
|
@@ -77,16 +106,30 @@ module ViewComponent
|
|
77
106
|
"elsif variant.to_sym == :#{variant}\n #{call_method_name(variant)}"
|
78
107
|
end.join("\n")
|
79
108
|
|
80
|
-
|
109
|
+
body = <<-RUBY
|
110
|
+
if variant.nil?
|
111
|
+
call
|
112
|
+
#{variant_elsifs}
|
113
|
+
else
|
114
|
+
call
|
115
|
+
end
|
116
|
+
RUBY
|
117
|
+
|
118
|
+
if development?
|
119
|
+
component_class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
81
120
|
def render_template_for(variant = nil)
|
82
|
-
|
83
|
-
|
84
|
-
#{variant_elsifs}
|
85
|
-
else
|
86
|
-
call
|
121
|
+
self.class.compiler.with_lock do
|
122
|
+
#{body}
|
87
123
|
end
|
88
124
|
end
|
89
|
-
|
125
|
+
RUBY
|
126
|
+
else
|
127
|
+
component_class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
128
|
+
def render_template_for(variant = nil)
|
129
|
+
#{body}
|
130
|
+
end
|
131
|
+
RUBY
|
132
|
+
end
|
90
133
|
end
|
91
134
|
|
92
135
|
def template_errors
|
@@ -95,7 +138,7 @@ module ViewComponent
|
|
95
138
|
errors = []
|
96
139
|
|
97
140
|
if (templates + inline_calls).empty?
|
98
|
-
errors << "
|
141
|
+
errors << "Couldn't find a template file or inline render method for #{component_class}."
|
99
142
|
end
|
100
143
|
|
101
144
|
if templates.count { |template| template[:variant].nil? } > 1
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "rails"
|
4
|
-
require "view_component"
|
5
4
|
|
6
5
|
module ViewComponent
|
7
6
|
class Engine < Rails::Engine # :nodoc:
|
@@ -116,6 +115,14 @@ module ViewComponent
|
|
116
115
|
end
|
117
116
|
end
|
118
117
|
|
118
|
+
initializer "compiler mode" do |app|
|
119
|
+
ViewComponent::Compiler.mode = if Rails.env.development? || Rails.env.test?
|
120
|
+
ViewComponent::Compiler::DEVELOPMENT_MODE
|
121
|
+
else
|
122
|
+
ViewComponent::Compiler::PRODUCTION_MODE
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
119
126
|
config.after_initialize do |app|
|
120
127
|
options = app.config.view_component
|
121
128
|
|
@@ -145,3 +152,14 @@ module ViewComponent
|
|
145
152
|
end
|
146
153
|
end
|
147
154
|
end
|
155
|
+
|
156
|
+
# :nocov:
|
157
|
+
unless defined?(ViewComponent::Base)
|
158
|
+
ActiveSupport::Deprecation.warn(
|
159
|
+
"This manually engine loading is deprecated and will be removed in v3.0.0. " \
|
160
|
+
"Remove `require \"view_component/engine\"`."
|
161
|
+
)
|
162
|
+
|
163
|
+
require "view_component"
|
164
|
+
end
|
165
|
+
# :nocov:
|
@@ -80,7 +80,7 @@ module ViewComponent # :nodoc:
|
|
80
80
|
if preview_path.nil?
|
81
81
|
raise(
|
82
82
|
PreviewTemplateError,
|
83
|
-
"A preview template for example #{example}
|
83
|
+
"A preview template for example #{example} doesn't exist.\n\n" \
|
84
84
|
"To fix this issue, create a template for the example."
|
85
85
|
)
|
86
86
|
end
|
@@ -20,7 +20,7 @@ module ViewComponent
|
|
20
20
|
# component, or a function that returns a component, we render that
|
21
21
|
# component instance, returning the string.
|
22
22
|
#
|
23
|
-
# If the slot renderable is a function and returns a string, it
|
23
|
+
# If the slot renderable is a function and returns a string, it's
|
24
24
|
# set as `@__vc_content` and is returned directly.
|
25
25
|
#
|
26
26
|
# If there is no slot renderable, we evaluate the block passed to
|
@@ -40,6 +40,8 @@ module ViewComponent
|
|
40
40
|
|
41
41
|
@content =
|
42
42
|
if defined?(@__vc_component_instance)
|
43
|
+
@__vc_component_instance.__vc_original_view_context = @parent.__vc_original_view_context
|
44
|
+
|
43
45
|
if defined?(@__vc_content_set_by_with_content)
|
44
46
|
@__vc_component_instance.with_content(@__vc_content_set_by_with_content)
|
45
47
|
|
@@ -69,7 +71,7 @@ module ViewComponent
|
|
69
71
|
|
70
72
|
# Allow access to public component methods via the wrapper
|
71
73
|
#
|
72
|
-
#
|
74
|
+
# for example
|
73
75
|
#
|
74
76
|
# calling `header.name` (where `header` is a slot) will call `name`
|
75
77
|
# on the `HeaderComponent` instance.
|
@@ -29,12 +29,12 @@ module ViewComponent
|
|
29
29
|
)
|
30
30
|
|
31
31
|
slot_names.each do |slot_name|
|
32
|
-
# Ensure slot_name
|
32
|
+
# Ensure slot_name isn't already declared
|
33
33
|
if self.slots.key?(slot_name)
|
34
34
|
raise ArgumentError.new("#{slot_name} slot declared multiple times")
|
35
35
|
end
|
36
36
|
|
37
|
-
# Ensure slot name
|
37
|
+
# Ensure slot name isn't :content
|
38
38
|
if slot_name == :content
|
39
39
|
raise ArgumentError.new ":content is a reserved slot name. Please use another name, such as ':body'"
|
40
40
|
end
|
@@ -105,7 +105,7 @@ module ViewComponent
|
|
105
105
|
# <% end %>
|
106
106
|
#
|
107
107
|
def slot(slot_name, **args, &block)
|
108
|
-
# Raise ArgumentError if `slot`
|
108
|
+
# Raise ArgumentError if `slot` doesn't exist
|
109
109
|
unless slots.keys.include?(slot_name)
|
110
110
|
raise ArgumentError.new "Unknown slot '#{slot_name}' - expected one of '#{slots.keys}'"
|
111
111
|
end
|
@@ -140,7 +140,7 @@ module ViewComponent
|
|
140
140
|
instance_variable_set(slot[:instance_variable_name], slot_instance)
|
141
141
|
end
|
142
142
|
|
143
|
-
# Return nil, as this method
|
143
|
+
# Return nil, as this method shouldn't output anything to the view itself.
|
144
144
|
nil
|
145
145
|
end
|
146
146
|
end
|
@@ -121,7 +121,7 @@ module ViewComponent
|
|
121
121
|
singular_name = ActiveSupport::Inflector.singularize(slot_name)
|
122
122
|
|
123
123
|
# Define setter for singular names
|
124
|
-
#
|
124
|
+
# for example `renders_many :items` allows fetching all tabs with
|
125
125
|
# `component.tabs` and setting a tab with `component.tab`
|
126
126
|
define_method singular_name do |*args, &block|
|
127
127
|
set_slot(slot_name, nil, *args, &block)
|
@@ -181,7 +181,7 @@ module ViewComponent
|
|
181
181
|
# If callable is a string, we assume it's referencing an internal class
|
182
182
|
slot[:renderable_class_name] = callable
|
183
183
|
elsif callable.respond_to?(:call)
|
184
|
-
# If slot
|
184
|
+
# If slot doesn't respond to `render_in`, we assume it's a proc,
|
185
185
|
# define a method, and save a reference to it to call when setting
|
186
186
|
method_name = :"_call_#{slot_name}"
|
187
187
|
define_method method_name, &callable
|
@@ -256,7 +256,7 @@ module ViewComponent
|
|
256
256
|
# 1. If this is a `content_area` style sub-component, we will render the
|
257
257
|
# block via the `slot`
|
258
258
|
#
|
259
|
-
# 2. Since we
|
259
|
+
# 2. Since we've to pass block content to components when calling
|
260
260
|
# `render`, evaluating the block here would require us to call
|
261
261
|
# `view_context.capture` twice, which is slower
|
262
262
|
slot.__vc_content_block = block if block_given?
|
@@ -38,7 +38,7 @@ module ViewComponent
|
|
38
38
|
# assert_text("Hello, World!")
|
39
39
|
# ```
|
40
40
|
#
|
41
|
-
# @param component [ViewComponent::Base] The instance of the component to be rendered.
|
41
|
+
# @param component [ViewComponent::Base, ViewComponent::Collection] The instance of the component to be rendered.
|
42
42
|
# @return [Nokogiri::HTML]
|
43
43
|
def render_inline(component, **args, &block)
|
44
44
|
@rendered_component =
|
@@ -103,7 +103,7 @@ module ViewComponent
|
|
103
103
|
@controller = old_controller
|
104
104
|
end
|
105
105
|
|
106
|
-
# Set the URL
|
106
|
+
# Set the URL of the current request (such as when using request-dependent path helpers):
|
107
107
|
#
|
108
108
|
# ```ruby
|
109
109
|
# with_request_url("/users/42") do
|
@@ -113,16 +113,22 @@ module ViewComponent
|
|
113
113
|
#
|
114
114
|
# @param path [String] The path to set for the current request.
|
115
115
|
def with_request_url(path)
|
116
|
+
old_request_path_info = request.path_info
|
116
117
|
old_request_path_parameters = request.path_parameters
|
117
118
|
old_request_query_parameters = request.query_parameters
|
119
|
+
old_request_query_string = request.query_string
|
118
120
|
old_controller = defined?(@controller) && @controller
|
119
121
|
|
122
|
+
request.path_info = path
|
120
123
|
request.path_parameters = Rails.application.routes.recognize_path(path)
|
121
124
|
request.set_header("action_dispatch.request.query_parameters", Rack::Utils.parse_query(path.split("?")[1]))
|
125
|
+
request.set_header(Rack::QUERY_STRING, path.split("?")[1])
|
122
126
|
yield
|
123
127
|
ensure
|
128
|
+
request.path_info = old_request_path_info
|
124
129
|
request.path_parameters = old_request_path_parameters
|
125
130
|
request.set_header("action_dispatch.request.query_parameters", old_request_query_parameters)
|
131
|
+
request.set_header(Rack::QUERY_STRING, old_request_query_string)
|
126
132
|
@controller = old_controller
|
127
133
|
end
|
128
134
|
|
data/lib/view_component.rb
CHANGED
@@ -19,4 +19,13 @@ module ViewComponent
|
|
19
19
|
autoload :Translatable
|
20
20
|
end
|
21
21
|
|
22
|
-
|
22
|
+
# :nocov:
|
23
|
+
if defined?(ViewComponent::Engine)
|
24
|
+
ActiveSupport::Deprecation.warn(
|
25
|
+
"This manually engine loading is deprecated and will be removed in v3.0.0. " \
|
26
|
+
"Remove `require \"view_component/engine\"`."
|
27
|
+
)
|
28
|
+
elsif defined?(Rails::Engine)
|
29
|
+
require "view_component/engine"
|
30
|
+
end
|
31
|
+
# :nocov:
|
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.48.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:
|
11
|
+
date: 2022-01-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -44,6 +44,20 @@ dependencies:
|
|
44
44
|
- - "~>"
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '1.0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: appraisal
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '2.4'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '2.4'
|
47
61
|
- !ruby/object:Gem::Dependency
|
48
62
|
name: benchmark-ips
|
49
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -268,7 +282,7 @@ dependencies:
|
|
268
282
|
- - ">="
|
269
283
|
- !ruby/object:Gem::Version
|
270
284
|
version: '0'
|
271
|
-
description:
|
285
|
+
description:
|
272
286
|
email:
|
273
287
|
- opensource+view_component@github.com
|
274
288
|
executables: []
|
@@ -295,6 +309,7 @@ files:
|
|
295
309
|
- lib/rails/generators/erb/templates/component.html.erb.tt
|
296
310
|
- lib/rails/generators/haml/component_generator.rb
|
297
311
|
- lib/rails/generators/haml/templates/component.html.haml.tt
|
312
|
+
- lib/rails/generators/locale/component_generator.rb
|
298
313
|
- lib/rails/generators/preview/component_generator.rb
|
299
314
|
- lib/rails/generators/preview/templates/component_preview.rb.tt
|
300
315
|
- lib/rails/generators/rspec/component_generator.rb
|
@@ -303,6 +318,8 @@ files:
|
|
303
318
|
- lib/rails/generators/slim/templates/component.html.slim.tt
|
304
319
|
- lib/rails/generators/stimulus/component_generator.rb
|
305
320
|
- lib/rails/generators/stimulus/templates/component_controller.js.tt
|
321
|
+
- lib/rails/generators/tailwindcss/component_generator.rb
|
322
|
+
- lib/rails/generators/tailwindcss/templates/component.html.erb.tt
|
306
323
|
- lib/rails/generators/test_unit/component_generator.rb
|
307
324
|
- lib/rails/generators/test_unit/templates/component_test.rb.tt
|
308
325
|
- lib/view_component.rb
|
@@ -341,7 +358,7 @@ licenses:
|
|
341
358
|
- MIT
|
342
359
|
metadata:
|
343
360
|
allowed_push_host: https://rubygems.org
|
344
|
-
post_install_message:
|
361
|
+
post_install_message:
|
345
362
|
rdoc_options: []
|
346
363
|
require_paths:
|
347
364
|
- lib
|
@@ -356,8 +373,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
356
373
|
- !ruby/object:Gem::Version
|
357
374
|
version: '0'
|
358
375
|
requirements: []
|
359
|
-
rubygems_version: 3.1.
|
360
|
-
signing_key:
|
376
|
+
rubygems_version: 3.1.4
|
377
|
+
signing_key:
|
361
378
|
specification_version: 4
|
362
379
|
summary: View components for Rails
|
363
380
|
test_files: []
|