view_component 2.37.0 → 2.41.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of view_component might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f97acb8cd2ac4c3c706207aa030cfb62af6d9066b9d05ed32b0946851132367
4
- data.tar.gz: aeceea89a252646b358b5a67883fc926bffd56d321e0e3237fbc1471970c6745
3
+ metadata.gz: ec24d635f8ce5341c3735ab855b9099fe2ea9179bb21a8fe79ba0f14f374ec44
4
+ data.tar.gz: fbc578b4554de38f01a4e92bbcf6ddfaf146ac04fb75e871f8d2378f8a19c053
5
5
  SHA512:
6
- metadata.gz: 8bc5f98ac1fc8ca620d2add5b59d5c0505489229cd0d8a7dcc9858774399c4e82e3dae419b5016b23a1228bec1e9e2e5a3e9d6980376439e5fb0cf02153ac8f9
7
- data.tar.gz: 4d7b0037a063825a777a94ca03e32e89abcadc04bb0c5ec2265f5eb8a1b62f7abb1e807ace75726365ab8baebdd774dd5fc757da2b0cd6ce51a5670b03309ff2
6
+ metadata.gz: 9ed08e30f614fc25aeb1c1826d159b312fba175a95a71966112069a27bc1da3255948b1c9504b06f55b6c476fda4418f13b3e42050664dc3146def0ff1ba0636
7
+ data.tar.gz: b02c7784cc31a3e5cfe5d6ec55879bbe832446557810a3884034e871effece891164424f4d4bf34664c3d8a239683405ea31d92b7351321ce0fc8c33c802f3a5
data/docs/CHANGELOG.md CHANGED
@@ -7,6 +7,88 @@ title: Changelog
7
7
 
8
8
  ## main
9
9
 
10
+ ## 2.41.0
11
+
12
+ * Add `sprockets-rails` development dependency to fix test suite failures when using rails@main.
13
+
14
+ *Blake Williams*
15
+
16
+ * Fix Ruby indentation warning.
17
+
18
+ *Blake Williams*
19
+
20
+ * Add `--parent` generator option to specify the parent class.
21
+ * Add config option `config.view_component.component_parent_class` to change it project-wide.
22
+
23
+ *Hans Lemuet*
24
+
25
+ * Update docs to add example for using Devise helpers in tests.
26
+
27
+ *Matthew Rider*
28
+
29
+ * Fix bug where `with_collection_parameter` did not inherit from parent component.
30
+
31
+ *Will Drexler*, *Christian Campoli*
32
+
33
+ * Allow query parameters in `with_request_url` test helper.
34
+
35
+ *Javi Martín*
36
+
37
+ * Add "how to render a component to a string" to FAQ.
38
+
39
+ *Hans Lemuet*
40
+
41
+ * Add `#render_in` to API docs.
42
+
43
+ *Hans Lemuet*
44
+
45
+ * Forward keyword arguments from slot wrapper to component instance.
46
+
47
+ *Cameron Dutro*
48
+
49
+ ## 2.40.0
50
+
51
+ * Replace antipatterns section in the documentation with best practices.
52
+
53
+ *Blake Williams*
54
+
55
+ * Add components to `rails stats` task.
56
+
57
+ *Nicolas Brousse*
58
+
59
+ * Fix bug when using Slim and writing a slot whose block evaluates to `nil`.
60
+
61
+ *Yousuf Jukaku*
62
+
63
+ * Add documentation for test helpers.
64
+
65
+ *Joel Hawksley*
66
+
67
+ ## 2.39.0
68
+
69
+ * Clarify documentation of `with_variant` as an override of Action Pack.
70
+
71
+ *Blake Williams*, *Cameron Dutro*, *Joel Hawksley*
72
+
73
+ * Update docs page to be called Javascript and CSS, rename Building ViewComponents to Guide.
74
+
75
+ *Joel Hawksley*
76
+
77
+ * Deprecate `Base#with_variant`.
78
+
79
+ *Cameron Dutro*
80
+
81
+ * Error out in the CI if docs/api.md has to be regenerated.
82
+
83
+ *Dany Marcoux*
84
+
85
+ ## 2.38.0
86
+
87
+ * Add `--stimulus` flag to the component generator. Generates a Stimulus controller alongside the component.
88
+ * Add config option `config.view_component.generate_stimulus_controller` to always generate a Stimulus controller.
89
+
90
+ *Sebastien Auriault*
91
+
10
92
  ## 2.37.0
11
93
 
12
94
  * Clarify slots example in docs to reduce naming confusion.
@@ -19,7 +101,7 @@ title: Changelog
19
101
 
20
102
  * Add test case for conflict with internal `@variant` variable.
21
103
 
22
- *David Backeus*
104
+ *David Backeus*
23
105
 
24
106
  * Document decision to not change naming convention recommendation to remove `-Component` suffix.
25
107
 
@@ -83,7 +165,7 @@ title: Changelog
83
165
 
84
166
  * Ensure consistent indentation with Rubocop.
85
167
 
86
- *Joel Hawksley
168
+ *Joel Hawksley*
87
169
 
88
170
  * Bump `activesupport` upper bound from `< 7.0` to `< 8.0`.
89
171
 
@@ -11,13 +11,21 @@ module ViewComponent
11
11
  private
12
12
 
13
13
  def destination
14
+ File.join(destination_directory, "#{destination_file_name}.html.#{engine_name}")
15
+ end
16
+
17
+ def destination_directory
14
18
  if options["sidecar"]
15
- File.join(component_path, class_path, "#{file_name}_component", "#{file_name}_component.html.#{engine_name}")
19
+ File.join(component_path, class_path, destination_file_name)
16
20
  else
17
- File.join(component_path, class_path, "#{file_name}_component.html.#{engine_name}")
21
+ File.join(component_path, class_path)
18
22
  end
19
23
  end
20
24
 
25
+ def destination_file_name
26
+ "#{file_name}_component"
27
+ end
28
+
21
29
  def file_name
22
30
  @_file_name ||= super.sub(/_component\z/i, "")
23
31
  end
@@ -25,5 +33,14 @@ module ViewComponent
25
33
  def component_path
26
34
  ViewComponent::Base.view_component_path
27
35
  end
36
+
37
+ def stimulus_controller
38
+ if options["stimulus"]
39
+ File.join(destination_directory, destination_file_name).
40
+ sub("#{component_path}/", "").
41
+ gsub("_", "-").
42
+ gsub("/", "--")
43
+ end
44
+ end
28
45
  end
29
46
  end
@@ -12,6 +12,9 @@ module Rails
12
12
  argument :attributes, type: :array, default: [], banner: "attribute"
13
13
  check_class_collision suffix: "Component"
14
14
  class_option :inline, type: :boolean, default: false
15
+ class_option :parent, type: :string, desc: "The parent class for the generated component"
16
+ class_option :stimulus, type: :boolean, default: ViewComponent::Base.generate_stimulus_controller
17
+ class_option :sidecar, type: :boolean, default: false
15
18
 
16
19
  def create_component_file
17
20
  template "component.rb", File.join(component_path, class_path, "#{file_name}_component.rb")
@@ -21,6 +24,8 @@ module Rails
21
24
 
22
25
  hook_for :preview, type: :boolean
23
26
 
27
+ hook_for :stimulus, type: :boolean
28
+
24
29
  hook_for :template_engine do |instance, template_engine|
25
30
  instance.invoke template_engine, [instance.name]
26
31
  end
@@ -28,7 +33,9 @@ module Rails
28
33
  private
29
34
 
30
35
  def parent_class
31
- defined?(ApplicationComponent) ? "ApplicationComponent" : "ViewComponent::Base"
36
+ return options[:parent] if options[:parent]
37
+
38
+ ViewComponent::Base.component_parent_class || default_parent_class
32
39
  end
33
40
 
34
41
  def initialize_signature
@@ -44,6 +51,10 @@ module Rails
44
51
  def initialize_call_method_for_inline?
45
52
  options["inline"]
46
53
  end
54
+
55
+ def default_parent_class
56
+ defined?(ApplicationComponent) ? ApplicationComponent : ViewComponent::Base
57
+ end
47
58
  end
48
59
  end
49
60
  end
@@ -8,7 +8,7 @@ class <%= class_name %>Component < <%= parent_class %>
8
8
  <%- end -%>
9
9
  <%- if initialize_call_method_for_inline? -%>
10
10
  def call
11
- content_tag :h1, "Hello world!"
11
+ content_tag :h1, "Hello world!"<%= ", data: { controller: \"#{stimulus_controller}\" }" if options["stimulus"] %>
12
12
  end
13
13
  <%- end -%>
14
14
 
@@ -11,6 +11,7 @@ module Erb
11
11
  source_root File.expand_path("templates", __dir__)
12
12
  class_option :sidecar, type: :boolean, default: false
13
13
  class_option :inline, type: :boolean, default: false
14
+ class_option :stimulus, type: :boolean, default: false
14
15
 
15
16
  def engine_name
16
17
  "erb"
@@ -19,6 +20,14 @@ module Erb
19
20
  def copy_view_file
20
21
  super
21
22
  end
23
+
24
+ private
25
+
26
+ def data_attributes
27
+ if options["stimulus"]
28
+ " data-controller=\"#{stimulus_controller}\""
29
+ end
30
+ end
22
31
  end
23
32
  end
24
33
  end
@@ -1 +1 @@
1
- <div>Add <%= class_name %> template here</div>
1
+ <div<%= data_attributes %>>Add <%= class_name %> template here</div>
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stimulus
4
+ module Generators
5
+ class ComponentGenerator < ::Rails::Generators::NamedBase
6
+ include ViewComponent::AbstractGenerator
7
+
8
+ source_root File.expand_path("templates", __dir__)
9
+ class_option :sidecar, type: :boolean, default: false
10
+
11
+ def create_stimulus_controller
12
+ template "component_controller.js", destination
13
+ end
14
+
15
+ private
16
+
17
+ def destination
18
+ if options["sidecar"]
19
+ File.join(component_path, class_path, "#{file_name}_component", "#{file_name}_component_controller.js")
20
+ else
21
+ File.join(component_path, class_path, "#{file_name}_component_controller.js")
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,7 @@
1
+ import { Controller } from "stimulus";
2
+
3
+ export default class extends Controller {
4
+ connect() {
5
+ console.log("Hello, Stimulus!", this.element);
6
+ }
7
+ }
@@ -39,29 +39,12 @@ module ViewComponent
39
39
 
40
40
  # Entrypoint for rendering components.
41
41
  #
42
- # view_context: ActionView context from calling view
43
- # block: optional block to be captured within the view context
42
+ # - `view_context`: ActionView context from calling view
43
+ # - `block`: optional block to be captured within the view context
44
44
  #
45
- # returns HTML that has been escaped by the respective template handler
45
+ # Returns HTML that has been escaped by the respective template handler.
46
46
  #
47
- # Example subclass:
48
- #
49
- # app/components/my_component.rb:
50
- # class MyComponent < ViewComponent::Base
51
- # def initialize(title:)
52
- # @title = title
53
- # end
54
- # end
55
- #
56
- # app/components/my_component.html.erb
57
- # <span title="<%= @title %>">Hello, <%= content %>!</span>
58
- #
59
- # In use:
60
- # <%= render MyComponent.new(title: "greeting") do %>world<% end %>
61
- # returns:
62
- # <span title="greeting">Hello, world!</span>
63
- #
64
- # @private
47
+ # @return [String]
65
48
  def render_in(view_context, &block)
66
49
  self.class.compile(raise_errors: true)
67
50
 
@@ -218,9 +201,14 @@ module ViewComponent
218
201
 
219
202
  # Use the provided variant instead of the one determined by the current request.
220
203
  #
204
+ # @deprecated Will be removed in v3.0.0.
221
205
  # @param variant [Symbol] The variant to be used by the component.
222
206
  # @return [self]
223
207
  def with_variant(variant)
208
+ ActiveSupport::Deprecation.warn(
209
+ "`with_variant` is deprecated and will be removed in ViewComponent v3.0.0."
210
+ )
211
+
224
212
  @__vc_variant = variant
225
213
 
226
214
  self
@@ -278,6 +266,14 @@ module ViewComponent
278
266
  #
279
267
  mattr_accessor :show_previews_source, instance_writer: false, default: false
280
268
 
269
+ # Always generate a Stimulus controller alongside the component:
270
+ #
271
+ # config.view_component.generate_stimulus_controller = true
272
+ #
273
+ # Defaults to `false`.
274
+ #
275
+ mattr_accessor :generate_stimulus_controller, instance_writer: false, default: false
276
+
281
277
  # Path for component files
282
278
  #
283
279
  # config.view_component.view_component_path = "app/my_components"
@@ -285,6 +281,14 @@ module ViewComponent
285
281
  # Defaults to "app/components".
286
282
  mattr_accessor :view_component_path, instance_writer: false, default: "app/components"
287
283
 
284
+ # Parent class for generated components
285
+ #
286
+ # config.view_component.component_parent_class = "MyBaseComponent"
287
+ #
288
+ # Defaults to "ApplicationComponent" if defined, "ViewComponent::Base" otherwise.
289
+ mattr_accessor :component_parent_class,
290
+ instance_writer: false
291
+
288
292
  class << self
289
293
  # @private
290
294
  attr_accessor :source_location, :virtual_path
@@ -371,6 +375,9 @@ module ViewComponent
371
375
  %r{(.*#{Regexp.quote(ViewComponent::Base.view_component_path)})|(\.rb)}, ""
372
376
  )
373
377
 
378
+ # Set collection parameter to the extended component
379
+ child.with_collection_parameter provided_collection_parameter
380
+
374
381
  super
375
382
  end
376
383
 
@@ -8,6 +8,10 @@ module ViewComponent
8
8
  config.view_component = ActiveSupport::OrderedOptions.new
9
9
  config.view_component.preview_paths ||= []
10
10
 
11
+ rake_tasks do
12
+ load "view_component/rails/tasks/view_component.rake"
13
+ end
14
+
11
15
  initializer "view_component.set_configs" do |app|
12
16
  options = app.config.view_component
13
17
 
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ task stats: "view_component:statsetup"
4
+
5
+ namespace :view_component do
6
+ task statsetup: :environment do
7
+ require "rails/code_statistics"
8
+
9
+ ::STATS_DIRECTORIES << ["ViewComponents", ViewComponent::Base.view_component_path]
10
+ end
11
+ end
@@ -62,9 +62,9 @@ module ViewComponent
62
62
  view_context.capture(&@__vc_content_block)
63
63
  elsif defined?(@__vc_content_set_by_with_content)
64
64
  @__vc_content_set_by_with_content
65
- end
65
+ end
66
66
 
67
- @content
67
+ @content = @content.to_s
68
68
  end
69
69
 
70
70
  # Allow access to public component methods via the wrapper
@@ -86,8 +86,14 @@ module ViewComponent
86
86
  # end
87
87
  # end
88
88
  #
89
- def method_missing(symbol, *args, &block)
90
- @__vc_component_instance.public_send(symbol, *args, &block)
89
+ if RUBY_VERSION >= "2.7.0"
90
+ def method_missing(symbol, *args, **kwargs, &block)
91
+ @__vc_component_instance.public_send(symbol, *args, **kwargs, &block)
92
+ end
93
+ else
94
+ def method_missing(symbol, *args, &block)
95
+ @__vc_component_instance.public_send(symbol, *args, &block)
96
+ end
91
97
  end
92
98
 
93
99
  def html_safe?
@@ -27,8 +27,19 @@ module ViewComponent
27
27
  # :nocov:
28
28
  end
29
29
 
30
+ # @private
30
31
  attr_reader :rendered_component
31
32
 
33
+ # Render a component inline. Internally sets `page` to be a `Capybara::Node::Simple`,
34
+ # allowing for Capybara assertions to be used:
35
+ #
36
+ # ```ruby
37
+ # render_inline(MyComponent.new)
38
+ # assert_text("Hello, World!")
39
+ # ```
40
+ #
41
+ # @param component [ViewComponent::Base] The instance of the component to be rendered.
42
+ # @return [Nokogiri::HTML]
32
43
  def render_inline(component, **args, &block)
33
44
  @rendered_component =
34
45
  if Rails.version.to_f >= 6.1
@@ -40,10 +51,12 @@ module ViewComponent
40
51
  Nokogiri::HTML.fragment(@rendered_component)
41
52
  end
42
53
 
54
+ # @private
43
55
  def controller
44
56
  @controller ||= build_controller(Base.test_controller.constantize)
45
57
  end
46
58
 
59
+ # @private
47
60
  def request
48
61
  @request ||=
49
62
  begin
@@ -53,6 +66,15 @@ module ViewComponent
53
66
  end
54
67
  end
55
68
 
69
+ # Set the Action Pack request variant for the given block:
70
+ #
71
+ # ```ruby
72
+ # with_variant(:phone) do
73
+ # render_inline(MyComponent.new)
74
+ # end
75
+ # ```
76
+ #
77
+ # @param variant [Symbol] The variant to be set for the provided block.
56
78
  def with_variant(variant)
57
79
  old_variants = controller.view_context.lookup_context.variants
58
80
 
@@ -62,6 +84,16 @@ module ViewComponent
62
84
  controller.view_context.lookup_context.variants = old_variants
63
85
  end
64
86
 
87
+ # Set the controller to be used while executing the given block,
88
+ # allowing access to controller-specific methods:
89
+ #
90
+ # ```ruby
91
+ # with_controller_class(UsersController) do
92
+ # render_inline(MyComponent.new)
93
+ # end
94
+ # ```
95
+ #
96
+ # @param klass [ActionController::Base] The controller to be used.
65
97
  def with_controller_class(klass)
66
98
  old_controller = defined?(@controller) && @controller
67
99
 
@@ -71,17 +103,30 @@ module ViewComponent
71
103
  @controller = old_controller
72
104
  end
73
105
 
106
+ # Set the URL for the current request (such as when using request-dependent path helpers):
107
+ #
108
+ # ```ruby
109
+ # with_request_url("/users/42") do
110
+ # render_inline(MyComponent.new)
111
+ # end
112
+ # ```
113
+ #
114
+ # @param path [String] The path to set for the current request.
74
115
  def with_request_url(path)
75
116
  old_request_path_parameters = request.path_parameters
117
+ old_request_query_parameters = request.query_parameters
76
118
  old_controller = defined?(@controller) && @controller
77
119
 
78
120
  request.path_parameters = Rails.application.routes.recognize_path(path)
121
+ request.set_header("action_dispatch.request.query_parameters", Rack::Utils.parse_query(path.split("?")[1]))
79
122
  yield
80
123
  ensure
81
124
  request.path_parameters = old_request_path_parameters
125
+ request.set_header("action_dispatch.request.query_parameters", old_request_query_parameters)
82
126
  @controller = old_controller
83
127
  end
84
128
 
129
+ # @private
85
130
  def build_controller(klass)
86
131
  klass.new.tap { |c| c.request = request }.extend(Rails.application.routes.url_helpers)
87
132
  end
@@ -3,7 +3,7 @@
3
3
  module ViewComponent
4
4
  module VERSION
5
5
  MAJOR = 2
6
- MINOR = 37
6
+ MINOR = 41
7
7
  PATCH = 0
8
8
 
9
9
  STRING = [MAJOR, MINOR, PATCH].join(".")
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.37.0
4
+ version: 2.41.0
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: 2021-08-09 00:00:00.000000000 Z
11
+ date: 2021-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -226,6 +226,20 @@ dependencies:
226
226
  - - "~>"
227
227
  - !ruby/object:Gem::Version
228
228
  version: '4.0'
229
+ - !ruby/object:Gem::Dependency
230
+ name: sprockets-rails
231
+ requirement: !ruby/object:Gem::Requirement
232
+ requirements:
233
+ - - "~>"
234
+ - !ruby/object:Gem::Version
235
+ version: 3.2.2
236
+ type: :development
237
+ prerelease: false
238
+ version_requirements: !ruby/object:Gem::Requirement
239
+ requirements:
240
+ - - "~>"
241
+ - !ruby/object:Gem::Version
242
+ version: 3.2.2
229
243
  - !ruby/object:Gem::Dependency
230
244
  name: yard
231
245
  requirement: !ruby/object:Gem::Requirement
@@ -287,6 +301,8 @@ files:
287
301
  - lib/rails/generators/rspec/templates/component_spec.rb.tt
288
302
  - lib/rails/generators/slim/component_generator.rb
289
303
  - lib/rails/generators/slim/templates/component.html.slim.tt
304
+ - lib/rails/generators/stimulus/component_generator.rb
305
+ - lib/rails/generators/stimulus/templates/component_controller.js.tt
290
306
  - lib/rails/generators/test_unit/component_generator.rb
291
307
  - lib/rails/generators/test_unit/templates/component_test.rb.tt
292
308
  - lib/view_component.rb
@@ -301,6 +317,7 @@ files:
301
317
  - lib/view_component/preview.rb
302
318
  - lib/view_component/preview_template_error.rb
303
319
  - lib/view_component/previewable.rb
320
+ - lib/view_component/rails/tasks/view_component.rake
304
321
  - lib/view_component/render_component_helper.rb
305
322
  - lib/view_component/render_component_to_string_helper.rb
306
323
  - lib/view_component/render_monkey_patch.rb