view_component 2.28.0 → 2.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0abc25e32e2befb60487f209469b2d9b96d6f1380a345466bcc816addc9f65d1
4
- data.tar.gz: a72e8ad8a5cfa1bbfd0bbbaa5510e14abd4818657b356681930537d8d5efa95e
3
+ metadata.gz: f8c387807061db7889dbc2e49ccb75a15a2cacd416048a6681b046eb321fb27b
4
+ data.tar.gz: fbddc58ff50b3ddaf615f773a681a7a8b7bef3972581dad8b87bf8425efff275
5
5
  SHA512:
6
- metadata.gz: 0b3f1cd9a86493fd5fbf68537536435c13b202bcba0d01e8d58f20ba0c158b7cdf1f878c75103d4b6a00f54e89227f7cb6b083bbbab17122e3e7f6b9d7c7f20d
7
- data.tar.gz: 4a29369a237c75889bce3a0777e5ff82e2bd7d25966ea31004fb293db5a6015aed2abd618340504ee89481d43970a35ff05c3aec2e113ff8b6378ed39415dfec
6
+ metadata.gz: 63a070fc0a5001b888dbd57a2a9fb0660b351a05b522d9a832efdd2a60f981d218eda2f500a50d01ca6a8c5ada4cccb61f2837e7b956215e89528d9454d3fd39
7
+ data.tar.gz: 8176f0427272a8305a520eeaa72ae58be2d9df42282a981f376eb69ac0543017f98d737ecb09f6fa6fc8cacf85adbbf82fbefe337da22432448ab361f35ae447
data/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  ## main
4
4
 
5
+ ## 2.29.0
6
+
7
+ * Allow Slot lambdas to share data from the parent component and allow chaining on the returned component.
8
+
9
+ *Sjors Baltus, Blake Williams*
10
+
11
+ * Experimental: Add `ViewComponent::Translatable`
12
+ * `t` and `translate` now will look first into the sidecar YAML translations file.
13
+ * `helpers.t` and `I18n.t` still reference the global Rails translation files.
14
+ * `l` and `localize` will still reference the global Rails translation files.
15
+
16
+ *Elia Schito*
17
+
18
+ * Fix rendering output of pass through slots when using HAML.
19
+
20
+ *Alex Robbin, Blake Williams*
21
+
22
+ * Experimental: call `._sidecar_files` to fetch the sidecar files for a given list of extensions, e.g. passing `["yml", "yaml"]`.
23
+
24
+ *Elia Schito*
25
+
26
+ * Fix bug where a single `jbuilder` template matched multiple template handlers.
27
+
28
+ *Niels Slot*
29
+
5
30
  ## 2.28.0
6
31
 
7
32
  * Include SlotableV2 by default in Base. **Note:** It's no longer necessary to include `ViewComponent::SlotableV2` to use Slots.
data/README.md CHANGED
@@ -6,14 +6,6 @@ A framework for building reusable, testable & encapsulated view components in Ru
6
6
 
7
7
  See [viewcomponent.org](https://viewcomponent.org/) for documentation.
8
8
 
9
- ## Installation
10
-
11
- In `Gemfile`, add:
12
-
13
- ```ruby
14
- gem "view_component", require: "view_component/engine"
15
- ```
16
-
17
9
  ## Contributing
18
10
 
19
11
  This project is intended to be a safe, welcoming space for collaboration. Contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. We recommend reading the [contributing guide](./CONTRIBUTING.md) as well.
@@ -12,4 +12,5 @@ module ViewComponent
12
12
  autoload :TestHelpers
13
13
  autoload :TestCase
14
14
  autoload :TemplateError
15
+ autoload :Translatable
15
16
  end
@@ -131,7 +131,7 @@ module ViewComponent
131
131
  @helpers ||= controller.view_context
132
132
  end
133
133
 
134
- # Exposes .virutal_path as an instance method
134
+ # Exposes .virtual_path as an instance method
135
135
  def virtual_path
136
136
  self.class.virtual_path
137
137
  end
@@ -206,6 +206,47 @@ module ViewComponent
206
206
  class << self
207
207
  attr_accessor :source_location, :virtual_path
208
208
 
209
+ # EXPERIMENTAL: This API is experimental and may be removed at any time.
210
+ # Find sidecar files for the given extensions.
211
+ #
212
+ # The provided array of extensions is expected to contain
213
+ # strings starting without the "dot", example: `["erb", "haml"]`.
214
+ #
215
+ # For example, one might collect sidecar CSS files that need to be compiled.
216
+ def _sidecar_files(extensions)
217
+ return [] unless source_location
218
+
219
+ extensions = extensions.join(",")
220
+
221
+ # view files in a directory named like the component
222
+ directory = File.dirname(source_location)
223
+ filename = File.basename(source_location, ".rb")
224
+ component_name = name.demodulize.underscore
225
+
226
+ # Add support for nested components defined in the same file.
227
+ #
228
+ # e.g.
229
+ #
230
+ # class MyComponent < ViewComponent::Base
231
+ # class MyOtherComponent < ViewComponent::Base
232
+ # end
233
+ # end
234
+ #
235
+ # Without this, `MyOtherComponent` will not look for `my_component/my_other_component.html.erb`
236
+ nested_component_files = if name.include?("::") && component_name != filename
237
+ Dir["#{directory}/#{filename}/#{component_name}.*{#{extensions}}"]
238
+ else
239
+ []
240
+ end
241
+
242
+ # view files in the same directory as the component
243
+ sidecar_files = Dir["#{directory}/#{component_name}.*{#{extensions}}"]
244
+
245
+ sidecar_directory_files = Dir["#{directory}/#{component_name}/#{filename}.*{#{extensions}}"]
246
+
247
+ (sidecar_files - [source_location] + sidecar_directory_files + nested_component_files).uniq
248
+ end
249
+
209
250
  # Render a component collection.
210
251
  def with_collection(collection, **args)
211
252
  Collection.new(self, collection, **args)
@@ -114,50 +114,18 @@ module ViewComponent
114
114
  end
115
115
 
116
116
  def templates
117
- @templates ||= matching_views_in_source_location.each_with_object([]) do |path, memo|
118
- pieces = File.basename(path).split(".")
119
-
120
- memo << {
121
- path: path,
122
- variant: pieces.second.split("+").second&.to_sym,
123
- handler: pieces.last
124
- }
125
- end
126
- end
127
-
128
- def matching_views_in_source_location
129
- source_location = component_class.source_location
130
- return [] unless source_location
131
-
132
- extensions = ActionView::Template.template_handler_extensions.join(",")
133
-
134
- # view files in a directory named like the component
135
- directory = File.dirname(source_location)
136
- filename = File.basename(source_location, ".rb")
137
- component_name = component_class.name.demodulize.underscore
138
-
139
- # Add support for nested components defined in the same file.
140
- #
141
- # e.g.
142
- #
143
- # class MyComponent < ViewComponent::Base
144
- # class MyOtherComponent < ViewComponent::Base
145
- # end
146
- # end
147
- #
148
- # Without this, `MyOtherComponent` will not look for `my_component/my_other_component.html.erb`
149
- nested_component_files = if component_class.name.include?("::") && component_name != filename
150
- Dir["#{directory}/#{filename}/#{component_name}.*{#{extensions}}"]
151
- else
152
- []
117
+ @templates ||= begin
118
+ extensions = ActionView::Template.template_handler_extensions
119
+
120
+ component_class._sidecar_files(extensions).each_with_object([]) do |path, memo|
121
+ pieces = File.basename(path).split(".")
122
+ memo << {
123
+ path: path,
124
+ variant: pieces.second.split("+").second&.to_sym,
125
+ handler: pieces.last
126
+ }
127
+ end
153
128
  end
154
-
155
- # view files in the same directory as the component
156
- sidecar_files = Dir["#{directory}/#{component_name}.*{#{extensions}}"]
157
-
158
- sidecar_directory_files = Dir["#{directory}/#{component_name}/#{filename}.*{#{extensions}}"]
159
-
160
- (sidecar_files - [source_location] + sidecar_directory_files + nested_component_files)
161
129
  end
162
130
 
163
131
  def inline_calls
@@ -25,19 +25,22 @@ module ViewComponent
25
25
  return @content if defined?(@content)
26
26
 
27
27
  view_context = @parent.send(:view_context)
28
- @content = view_context.capture do
29
- if defined?(@_component_instance)
30
- # render_in is faster than `parent.render`
31
- if defined?(@_content_block)
28
+
29
+ @content = if defined?(@_component_instance)
30
+ # render_in is faster than `parent.render`
31
+ if defined?(@_content_block)
32
+ view_context.capture do
32
33
  @_component_instance.render_in(view_context, &@_content_block)
33
- else
34
+ end
35
+ else
36
+ view_context.capture do
34
37
  @_component_instance.render_in(view_context)
35
38
  end
36
- elsif defined?(@_content)
37
- @_content
38
- elsif defined?(@_content_block)
39
- @_content_block.call
40
39
  end
40
+ elsif defined?(@_content)
41
+ @_content
42
+ elsif defined?(@_content_block)
43
+ view_context.capture(&@_content_block)
41
44
  end
42
45
 
43
46
  @content
@@ -227,7 +227,9 @@ module ViewComponent
227
227
  # current component. This is necessary to allow the lambda to access helper
228
228
  # methods like `content_tag` as well as parent component state.
229
229
  renderable_value = if block_given?
230
- slot_definition[:renderable_function].bind(self).call(*args, **kwargs) { view_context.capture(&block) }
230
+ slot_definition[:renderable_function].bind(self).call(*args, **kwargs) do |*args, **kwargs|
231
+ view_context.capture(*args, **kwargs, &block)
232
+ end
231
233
  else
232
234
  slot_definition[:renderable_function].bind(self).call(*args, **kwargs)
233
235
  end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+ require "i18n"
5
+ require "action_view/helpers/translation_helper"
6
+ require "active_support/concern"
7
+
8
+ module ViewComponent
9
+ module Translatable
10
+ extend ActiveSupport::Concern
11
+
12
+ included do
13
+ class_attribute :i18n_backend, instance_writer: false, instance_predicate: false
14
+ end
15
+
16
+ class_methods do
17
+ def i18n_scope
18
+ @i18n_scope ||= virtual_path.sub(%r{^/}, "").gsub(%r{/_?}, ".")
19
+ end
20
+
21
+ def _after_compile
22
+ super
23
+
24
+ unless CompileCache.compiled? self
25
+ self.i18n_backend = I18nBackend.new(
26
+ i18n_scope: i18n_scope,
27
+ load_paths: _sidecar_files(%w[yml yaml]),
28
+ )
29
+ end
30
+ end
31
+ end
32
+
33
+ class I18nBackend < ::I18n::Backend::Simple
34
+ EMPTY_HASH = {}.freeze
35
+
36
+ def initialize(i18n_scope:, load_paths:)
37
+ @i18n_scope = i18n_scope.split(".")
38
+ @load_paths = load_paths
39
+ end
40
+
41
+ # Ensure the Simple backend won't load paths from ::I18n.load_path
42
+ def load_translations
43
+ super(@load_paths)
44
+ end
45
+
46
+ def scope_data(data)
47
+ @i18n_scope.reverse_each do |part|
48
+ data = { part => data}
49
+ end
50
+ data
51
+ end
52
+
53
+ def store_translations(locale, data, options = EMPTY_HASH)
54
+ super(locale, scope_data(data), options)
55
+ end
56
+ end
57
+
58
+ def translate(key = nil, locale: nil, **options)
59
+ locale ||= ::I18n.locale
60
+
61
+ key = "#{i18n_scope}#{key}" if key.start_with?(".")
62
+
63
+ result = catch(:exception) do
64
+ i18n_backend.translate(locale, key, options)
65
+ end
66
+
67
+ # Fallback to the global translations
68
+ if result.is_a? ::I18n::MissingTranslation
69
+ result = helpers.t(key, locale: locale, **options)
70
+ end
71
+
72
+ result
73
+ end
74
+ alias :t :translate
75
+
76
+ # Exposes .i18n_scope as an instance method
77
+ def i18n_scope
78
+ self.class.i18n_scope
79
+ end
80
+ end
81
+ end
@@ -3,7 +3,7 @@
3
3
  module ViewComponent
4
4
  module VERSION
5
5
  MAJOR = 2
6
- MINOR = 28
6
+ MINOR = 29
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.28.0
4
+ version: 2.29.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-03-16 00:00:00.000000000 Z
11
+ date: 2021-04-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -128,6 +128,20 @@ dependencies:
128
128
  - - "~>"
129
129
  - !ruby/object:Gem::Version
130
130
  version: '1'
131
+ - !ruby/object:Gem::Dependency
132
+ name: jbuilder
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '2'
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: '2'
131
145
  - !ruby/object:Gem::Dependency
132
146
  name: rubocop
133
147
  requirement: !ruby/object:Gem::Requirement
@@ -249,6 +263,7 @@ files:
249
263
  - lib/view_component/template_error.rb
250
264
  - lib/view_component/test_case.rb
251
265
  - lib/view_component/test_helpers.rb
266
+ - lib/view_component/translatable.rb
252
267
  - lib/view_component/version.rb
253
268
  homepage: https://github.com/github/view_component
254
269
  licenses: