style_capsule 1.4.0 → 2.0.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.
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "digest/sha1"
4
+ require_relative "component_class_methods"
4
5
  # ActiveSupport string extensions are conditionally required in lib/style_capsule.rb
5
6
 
6
7
  module StyleCapsule
@@ -95,314 +96,7 @@ module StyleCapsule
95
96
  end
96
97
 
97
98
  module ClassMethods
98
- # Class-level cache for scoped CSS per component class
99
- def css_cache
100
- @css_cache ||= {}
101
- end
102
-
103
- # Clear the CSS cache for this component class
104
- #
105
- # Useful for testing or when you want to force CSS reprocessing.
106
- # In development, this is automatically called when classes are reloaded.
107
- #
108
- # @example
109
- # MyComponent.clear_css_cache
110
- def clear_css_cache
111
- @css_cache = {}
112
- end
113
-
114
- # Set or get a custom capsule ID for this component class (useful for testing)
115
- #
116
- # @param capsule_id [String, nil] The custom capsule ID to use (nil to get current value)
117
- # @return [String, nil] The current capsule ID if no argument provided
118
- # @example Setting a custom capsule ID
119
- # class MyComponent < ApplicationComponent
120
- # include StyleCapsule::ViewComponent
121
- # capsule_id "test-capsule-123"
122
- # end
123
- # @example Getting the current capsule ID
124
- # MyComponent.capsule_id # => "test-capsule-123" or nil
125
- def capsule_id(capsule_id = nil)
126
- if capsule_id.nil?
127
- @custom_capsule_id if defined?(@custom_capsule_id)
128
- else
129
- @custom_capsule_id = capsule_id.to_s
130
- end
131
- end
132
-
133
- # Configure stylesheet registry for head rendering
134
- #
135
- # Enables head rendering and configures namespace and cache strategy in a single call.
136
- # All parameters are optional - calling without arguments enables head rendering with defaults.
137
- #
138
- # @param namespace [Symbol, String, nil] Namespace identifier (nil/blank uses default)
139
- # @param cache_strategy [Symbol, String, Proc, nil] Cache strategy: :none (default), :time, :proc, :file
140
- # - Symbol or String: :none, :time, :proc, :file (or "none", "time", "proc", "file")
141
- # - Proc: Custom cache proc (automatically uses :proc strategy)
142
- # Proc receives: (css_content, capsule_id, namespace) and should return [cache_key, should_cache, expires_at]
143
- # @param cache_ttl [Integer, ActiveSupport::Duration, nil] Time-to-live in seconds (for :time strategy). Supports ActiveSupport::Duration (e.g., 1.hour, 30.minutes)
144
- # @param cache_proc [Proc, nil] Custom cache proc (for :proc strategy, ignored if cache_strategy is a Proc)
145
- # Proc receives: (css_content, capsule_id, namespace) and should return [cache_key, should_cache, expires_at]
146
- # @return [void]
147
- # @example Basic usage (enables head rendering with defaults)
148
- # class MyComponent < ApplicationComponent
149
- # include StyleCapsule::ViewComponent
150
- # stylesheet_registry
151
- # end
152
- # @example With namespace
153
- # class AdminComponent < ApplicationComponent
154
- # include StyleCapsule::ViewComponent
155
- # stylesheet_registry namespace: :admin
156
- # end
157
- # @example With time-based caching
158
- # class MyComponent < ApplicationComponent
159
- # include StyleCapsule::ViewComponent
160
- # stylesheet_registry cache_strategy: :time, cache_ttl: 1.hour
161
- # end
162
- # @example With custom proc caching
163
- # class MyComponent < ApplicationComponent
164
- # include StyleCapsule::ViewComponent
165
- # stylesheet_registry cache_strategy: :proc, cache_proc: ->(css, capsule_id, ns) {
166
- # cache_key = "css_#{capsule_id}_#{ns}"
167
- # should_cache = css.length > 100
168
- # expires_at = Time.now + 1800
169
- # [cache_key, should_cache, expires_at]
170
- # }
171
- # end
172
- # @example File-based caching (requires class method component_styles)
173
- # class MyComponent < ApplicationComponent
174
- # include StyleCapsule::ViewComponent
175
- # stylesheet_registry cache_strategy: :file
176
- #
177
- # def self.component_styles # Must be class method for file caching
178
- # <<~CSS
179
- # .section { color: red; }
180
- # CSS
181
- # end
182
- # end
183
- # @example All options combined
184
- # class MyComponent < ApplicationComponent
185
- # include StyleCapsule::ViewComponent
186
- # stylesheet_registry namespace: :admin, cache_strategy: :time, cache_ttl: 1.hour
187
- # end
188
- def stylesheet_registry(namespace: nil, cache_strategy: :none, cache_ttl: nil, cache_proc: nil)
189
- @head_rendering = true
190
- @stylesheet_namespace = namespace unless namespace.nil?
191
-
192
- # Normalize cache_strategy: convert strings to symbols, handle Proc
193
- normalized_strategy, normalized_proc = normalize_cache_strategy(cache_strategy, cache_proc)
194
- @inline_cache_strategy = normalized_strategy
195
- @inline_cache_ttl = cache_ttl
196
- @inline_cache_proc = normalized_proc
197
- end
198
-
199
- private
200
-
201
- # Normalize cache_strategy to handle Symbol, String, and Proc
202
- #
203
- # @param cache_strategy [Symbol, String, Proc, nil] Cache strategy
204
- # @param cache_proc [Proc, nil] Optional cache proc (ignored if cache_strategy is a Proc)
205
- # @return [Array<Symbol, Proc|nil>] Normalized strategy and proc
206
- def normalize_cache_strategy(cache_strategy, cache_proc)
207
- case cache_strategy
208
- when Proc
209
- # If cache_strategy is a Proc, use it as the proc and set strategy to :proc
210
- [:proc, cache_strategy]
211
- when String
212
- # Convert string to symbol
213
- normalized = cache_strategy.to_sym
214
- unless [:none, :time, :proc, :file].include?(normalized)
215
- raise ArgumentError, "cache_strategy must be :none, :time, :proc, or :file (got: #{cache_strategy.inspect})"
216
- end
217
- [normalized, cache_proc]
218
- when Symbol
219
- unless [:none, :time, :proc, :file].include?(cache_strategy)
220
- raise ArgumentError, "cache_strategy must be :none, :time, :proc, or :file (got: #{cache_strategy.inspect})"
221
- end
222
- [cache_strategy, cache_proc]
223
- when nil
224
- [:none, nil]
225
- else
226
- raise ArgumentError, "cache_strategy must be a Symbol, String, or Proc (got: #{cache_strategy.class})"
227
- end
228
- end
229
-
230
- # Check if component uses head rendering (checks instance variable, then parent class, defaults to false)
231
- #
232
- # @return [Boolean] Whether head rendering is enabled (default: false)
233
- def head_rendering?
234
- if defined?(@head_rendering)
235
- @head_rendering
236
- elsif superclass.respond_to?(:head_rendering?, true)
237
- superclass.head_rendering?
238
- else
239
- false
240
- end
241
- end
242
-
243
- public :head_rendering?
244
-
245
- # Get the namespace for stylesheet registry (checks instance variable, then parent class, defaults to nil)
246
- #
247
- # @return [Symbol, String, nil] The namespace identifier (default: nil)
248
- def stylesheet_namespace
249
- if defined?(@stylesheet_namespace) && @stylesheet_namespace
250
- @stylesheet_namespace
251
- elsif superclass.respond_to?(:stylesheet_namespace, true)
252
- superclass.stylesheet_namespace
253
- end
254
- end
255
-
256
- # Configure StyleCapsule settings
257
- #
258
- # All settings support class inheritance - child classes inherit settings from parent classes
259
- # and can override them by calling style_capsule again with different values.
260
- #
261
- # @param namespace [Symbol, String, nil] Default namespace for stylesheets
262
- # @param cache_strategy [Symbol, String, Proc, nil] Cache strategy: :none (default), :time, :proc, :file
263
- # @param cache_ttl [Integer, ActiveSupport::Duration, nil] Time-to-live in seconds (for :time strategy)
264
- # @param cache_proc [Proc, nil] Custom cache proc (for :proc strategy)
265
- # @param scoping_strategy [Symbol, nil] CSS scoping strategy: :selector_patching (default) or :nesting
266
- # @param head_rendering [Boolean, nil] Enable head rendering (default: true if any option is set, false otherwise)
267
- # @return [void]
268
- # @example Basic usage with namespace
269
- # class AdminComponent < ApplicationComponent
270
- # include StyleCapsule::ViewComponent
271
- # style_capsule namespace: :admin
272
- #
273
- # def call
274
- # register_stylesheet("stylesheets/admin/dashboard") # Uses :admin namespace automatically
275
- # content_tag(:div, "Content")
276
- # end
277
- # end
278
- # @example With all options
279
- # class MyComponent < ApplicationComponent
280
- # include StyleCapsule::ViewComponent
281
- # style_capsule(
282
- # namespace: :user,
283
- # cache_strategy: :time,
284
- # cache_ttl: 1.hour,
285
- # scoping_strategy: :nesting
286
- # )
287
- # end
288
- # @example Inheritance - child class inherits parent settings
289
- # class BaseComponent < ApplicationComponent
290
- # include StyleCapsule::ViewComponent
291
- # style_capsule namespace: :admin, cache_strategy: :time, cache_ttl: 1.hour
292
- # end
293
- #
294
- # class ChildComponent < BaseComponent
295
- # # Inherits namespace: :admin, cache_strategy: :time, cache_ttl: 1.hour
296
- # # Can override specific settings:
297
- # style_capsule namespace: :user # Overrides namespace, keeps cache settings
298
- # end
299
- def style_capsule(namespace: nil, cache_strategy: nil, cache_ttl: nil, cache_proc: nil, scoping_strategy: nil, head_rendering: nil)
300
- # Set namespace (stored in instance variable, but getter checks parent class for inheritance)
301
- if namespace
302
- @stylesheet_namespace = namespace
303
- end
304
-
305
- # Configure cache strategy if provided
306
- if cache_strategy || cache_ttl || cache_proc
307
- normalized_strategy, normalized_proc = normalize_cache_strategy(cache_strategy || :none, cache_proc)
308
- @inline_cache_strategy = normalized_strategy
309
- # Explicitly set cache_ttl (even if nil) to override parent's value when cache settings are changed
310
- @inline_cache_ttl = cache_ttl
311
- @inline_cache_proc = normalized_proc
312
- end
313
-
314
- # Configure CSS scoping strategy if provided
315
- if scoping_strategy
316
- unless [:selector_patching, :nesting].include?(scoping_strategy)
317
- raise ArgumentError, "scoping_strategy must be :selector_patching or :nesting (got: #{scoping_strategy.inspect})"
318
- end
319
- @css_scoping_strategy = scoping_strategy
320
- end
321
-
322
- # Enable head rendering if explicitly set or if any option is provided (except scoping_strategy)
323
- if head_rendering.nil?
324
- @head_rendering = true if namespace || cache_strategy || cache_ttl || cache_proc
325
- else
326
- @head_rendering = head_rendering
327
- end
328
- end
329
-
330
- # Get the custom scope ID if set (alias for capsule_id getter)
331
- def custom_capsule_id
332
- @custom_capsule_id if defined?(@custom_capsule_id)
333
- end
334
-
335
- # Get inline cache strategy (checks instance variable, then parent class, defaults to nil)
336
- #
337
- # @return [Symbol, nil] The cache strategy (default: nil)
338
- def inline_cache_strategy
339
- if defined?(@inline_cache_strategy) && @inline_cache_strategy
340
- @inline_cache_strategy
341
- elsif superclass.respond_to?(:inline_cache_strategy, true)
342
- superclass.inline_cache_strategy
343
- end
344
- end
345
-
346
- # Get inline cache TTL (checks instance variable, then parent class, defaults to nil)
347
- #
348
- # @return [Integer, ActiveSupport::Duration, nil] The cache TTL (default: nil)
349
- def inline_cache_ttl
350
- if defined?(@inline_cache_ttl)
351
- @inline_cache_ttl
352
- elsif superclass.respond_to?(:inline_cache_ttl, true)
353
- superclass.inline_cache_ttl
354
- end
355
- end
356
-
357
- # Get inline cache proc (checks instance variable, then parent class, defaults to nil)
358
- #
359
- # @return [Proc, nil] The cache proc (default: nil)
360
- def inline_cache_proc
361
- if defined?(@inline_cache_proc)
362
- @inline_cache_proc
363
- elsif superclass.respond_to?(:inline_cache_proc, true)
364
- superclass.inline_cache_proc
365
- end
366
- end
367
-
368
- public :head_rendering?, :stylesheet_namespace, :style_capsule, :custom_capsule_id, :inline_cache_strategy, :inline_cache_ttl, :inline_cache_proc
369
-
370
- # Get CSS scoping strategy (checks instance variable, then parent class, defaults to :selector_patching)
371
- #
372
- # @return [Symbol] The current scoping strategy (default: :selector_patching)
373
- def css_scoping_strategy
374
- if defined?(@css_scoping_strategy) && @css_scoping_strategy
375
- @css_scoping_strategy
376
- elsif superclass.respond_to?(:css_scoping_strategy, true)
377
- superclass.css_scoping_strategy
378
- else
379
- :selector_patching
380
- end
381
- end
382
-
383
- public :css_scoping_strategy
384
-
385
- # Set or get options for stylesheet_link_tag when using file-based caching
386
- #
387
- # @param options [Hash, nil] Options to pass to stylesheet_link_tag (e.g., "data-turbo-track": "reload", omit to get current value)
388
- # @return [Hash, nil] The current stylesheet link options if no argument provided
389
- # @example Setting stylesheet link options
390
- # class MyComponent < ApplicationComponent
391
- # include StyleCapsule::ViewComponent
392
- # stylesheet_registry cache_strategy: :file
393
- # stylesheet_link_options "data-turbo-track": "reload"
394
- # end
395
- # @example Getting the current options
396
- # MyComponent.stylesheet_link_options # => {"data-turbo-track" => "reload"} or nil
397
- def stylesheet_link_options(options = nil)
398
- if options.nil?
399
- @stylesheet_link_options if defined?(@stylesheet_link_options)
400
- else
401
- @stylesheet_link_options = options
402
- end
403
- end
404
-
405
- public :stylesheet_link_options
99
+ include StyleCapsule::ComponentClassMethods
406
100
  end
407
101
 
408
102
  # Module that wraps call to add scoped wrapper
@@ -415,8 +109,11 @@ module StyleCapsule
415
109
  # Get content from original call method
416
110
  content_html = super
417
111
 
112
+ # Get wrapper tag
113
+ tag = self.class.wrapper_tag
114
+
418
115
  # Wrap content in scoped element
419
- scoped_wrapper = helpers.content_tag(:div, content_html.html_safe, data: {capsule: component_capsule})
116
+ scoped_wrapper = helpers.content_tag(tag, content_html.html_safe, data: {capsule: component_capsule})
420
117
 
421
118
  # Combine styles and wrapped content
422
119
  (styles_html + scoped_wrapper).html_safe
@@ -450,6 +147,7 @@ module StyleCapsule
450
147
  # File caching is only allowed for class method component_styles.
451
148
  #
452
149
  # @return [String] HTML string with style tag or empty string
150
+ # rubocop:disable Metrics/AbcSize -- coordinates head vs body rendering, caching, and registry
453
151
  def render_capsule_styles
454
152
  css_content = component_styles_content
455
153
  return "".html_safe if css_content.nil? || css_content.to_s.strip.empty?
@@ -495,6 +193,7 @@ module StyleCapsule
495
193
  helpers.content_tag(:style, scoped_css.html_safe, type: "text/css")
496
194
  end
497
195
  end
196
+ # rubocop:enable Metrics/AbcSize
498
197
 
499
198
  # Check if component should use head rendering
500
199
  #
@@ -506,11 +205,10 @@ module StyleCapsule
506
205
 
507
206
  # Scope CSS and return scoped CSS with attribute selectors
508
207
  def scope_css(css_content)
509
- # Use class-level cache to avoid reprocessing same CSS
510
- # Include capsule_id and scoping strategy in cache key
511
208
  capsule_id = component_capsule
512
209
  scoping_strategy = self.class.css_scoping_strategy
513
- cache_key = "#{self.class.name}:#{capsule_id}:#{scoping_strategy}"
210
+ css_fingerprint = Digest::SHA1.hexdigest(css_content.to_s)
211
+ cache_key = "#{self.class.name}:#{capsule_id}:#{scoping_strategy}:#{css_fingerprint}"
514
212
 
515
213
  if self.class.css_cache.key?(cache_key)
516
214
  return self.class.css_cache[cache_key]
@@ -519,15 +217,12 @@ module StyleCapsule
519
217
  # Use the configured scoping strategy
520
218
  scoped_css = case scoping_strategy
521
219
  when :nesting
522
- CssProcessor.scope_with_nesting(css_content, capsule_id)
220
+ CssProcessor.scope_with_nesting(css_content, capsule_id, component_class: self.class)
523
221
  else # :selector_patching (default)
524
- CssProcessor.scope_selectors(css_content, capsule_id)
222
+ CssProcessor.scope_selectors(css_content, capsule_id, component_class: self.class)
525
223
  end
526
224
 
527
- # Cache at class level (one style block per component type/scope/strategy combination)
528
- self.class.css_cache[cache_key] = scoped_css
529
-
530
- scoped_css
225
+ self.class.store_css_cache(cache_key, scoped_css)
531
226
  end
532
227
 
533
228
  # Generate a unique capsule ID based on component class name (per-component-type)
@@ -15,7 +15,7 @@ module StyleCapsule
15
15
  #
16
16
  # Usage in ViewComponent components:
17
17
  # class MyComponent < ApplicationComponent
18
- # styles_namespace :user # Set default namespace
18
+ # style_capsule namespace: :user # Set default namespace for register_stylesheet
19
19
  #
20
20
  # def call
21
21
  # register_stylesheet("stylesheets/user/my_component") # Uses :user namespace automatically
@@ -32,7 +32,7 @@ module StyleCapsule
32
32
  # content_tag(:div, "Content")
33
33
  # end
34
34
  #
35
- # If the component has a default namespace set via styles_namespace or stylesheet_registry,
35
+ # If the component has a default namespace set via style_capsule or stylesheet_registry,
36
36
  # it will be used automatically when namespace is not explicitly provided.
37
37
  #
38
38
  # @param file_path [String] Path to stylesheet (relative to app/assets/stylesheets)
data/lib/style_capsule.rb CHANGED
@@ -72,9 +72,12 @@ end
72
72
  # <%= stylesheet_registry_tags(namespace: :admin) %>
73
73
  #
74
74
  # @example Namespace Support
75
- # # Register stylesheets with namespaces
76
- # StyleCapsule::StylesheetRegistry.register('stylesheets/admin/dashboard', namespace: :admin)
77
- # StyleCapsule::StylesheetRegistry.register('stylesheets/user/profile', namespace: :user)
75
+ # # Eager registrations (boot / class load; process-wide manifest)
76
+ # StyleCapsule::StylesheetRegistry.register_eager('stylesheets/admin/dashboard', namespace: :admin)
77
+ # StyleCapsule::StylesheetRegistry.register_eager('stylesheets/user/profile', namespace: :user)
78
+ #
79
+ # # Render-time registrations (request-scoped; also picked up by HeadInjectionMiddleware)
80
+ # StyleCapsule::StylesheetRegistry.register('stylesheets/page', namespace: :user)
78
81
  #
79
82
  # # Render all namespaces (default)
80
83
  # <%= stylesheet_registry_tags %>
@@ -85,7 +88,7 @@ end
85
88
  # @example File-Based Caching (HTTP Caching)
86
89
  # class MyComponent < ApplicationComponent
87
90
  # include StyleCapsule::Component
88
- # stylesheet_registry cache_strategy: :file # Writes CSS to files for HTTP caching
91
+ # style_capsule cache_strategy: :file # Writes CSS to files for HTTP caching
89
92
  # end
90
93
  #
91
94
  # # CSS files are written to app/assets/builds/capsules/
@@ -94,6 +97,8 @@ end
94
97
  module StyleCapsule
95
98
  require_relative "style_capsule/version"
96
99
  require_relative "style_capsule/instrumentation"
100
+ require_relative "style_capsule/asset_path"
101
+ require_relative "style_capsule/helper_scope_cache"
97
102
  require_relative "style_capsule/css_processor"
98
103
  require_relative "style_capsule/css_file_writer"
99
104
  require_relative "style_capsule/stylesheet_registry"
@@ -16,7 +16,20 @@ namespace :style_capsule do
16
16
  end
17
17
  end
18
18
 
19
- # Hook into Rails asset precompilation (similar to Tailwind CSS)
19
+ # Hook into Rails asset precompilation (similar to Tailwind CSS).
20
+ # Set `config.style_capsule.run_on_precompile = false` to skip.
21
+ task "style_capsule:precompile_hook" => :environment do
22
+ cfg = Rails.application.config
23
+ run = if cfg.respond_to?(:style_capsule) && cfg.style_capsule
24
+ cfg.style_capsule.run_on_precompile != false
25
+ else
26
+ true
27
+ end
28
+ next unless run
29
+
30
+ Rake::Task["style_capsule:build"].invoke
31
+ end
32
+
20
33
  if defined?(Rails)
21
- Rake::Task["assets:precompile"].enhance(["style_capsule:build"]) if Rake::Task.task_defined?("assets:precompile")
34
+ Rake::Task["assets:precompile"].enhance(["style_capsule:precompile_hook"]) if Rake::Task.task_defined?("assets:precompile")
22
35
  end
@@ -1,9 +1,13 @@
1
1
  module StyleCapsule
2
2
  VERSION: String
3
3
 
4
+ module AssetPath
5
+ def self.validate_logical_path!: (String path) -> String
6
+ end
7
+
4
8
  module CssProcessor
5
- def self.scope_selectors: (String css_string, String capsule_id) -> String
6
- def self.scope_with_nesting: (String css_string, String capsule_id) -> String
9
+ def self.scope_selectors: (String css_string, String capsule_id, ?component_class: Class | String | nil) -> String
10
+ def self.scope_with_nesting: (String css_string, String capsule_id, ?component_class: Class | String | nil) -> String
7
11
  def self.strip_comments: (String css) -> String
8
12
  end
9
13
 
@@ -17,43 +21,59 @@ module StyleCapsule
17
21
  def self.enabled?: () -> bool
18
22
  end
19
23
 
20
- class StylesheetRegistry < ActiveSupport::CurrentAttributes
24
+ # At runtime inherits Object when ActiveSupport::CurrentAttributes is unavailable.
25
+ class StylesheetRegistry
21
26
  DEFAULT_NAMESPACE: Symbol
22
27
 
23
28
  def self.normalize_namespace: (Symbol | String | nil namespace) -> Symbol
24
29
  def self.register: (String file_path, ?namespace: Symbol | String | nil, **Hash[untyped, untyped] options) -> void
30
+ def self.register_eager: (String file_path, ?namespace: Symbol | String | nil, **Hash[untyped, untyped] options) -> void
25
31
  def self.register_inline: (String css_content, ?namespace: Symbol | String | nil, ?capsule_id: String | nil, ?cache_key: String | nil, ?cache_strategy: Symbol, ?cache_ttl: Integer | ActiveSupport::Duration | nil, ?cache_proc: Proc | nil, ?component_class: Class | nil, ?stylesheet_link_options: Hash[untyped, untyped] | nil) -> void
26
32
  def self.cached_inline: (String cache_key, cache_strategy: Symbol, ?cache_ttl: Integer | ActiveSupport::Duration | nil, ?cache_proc: Proc | nil, ?css_content: String | nil, ?capsule_id: String | nil, ?namespace: Symbol | nil) -> String | nil
27
33
  def self.cache_inline_css: (String cache_key, String css_content, cache_strategy: Symbol, ?cache_ttl: Integer | ActiveSupport::Duration | nil, ?cache_proc: Proc | nil, ?capsule_id: String | nil, ?namespace: Symbol | nil) -> void
28
34
  def self.clear_inline_cache: (?String cache_key) -> void
29
35
  def self.cleanup_expired_cache: () -> Integer
30
- def self.manifest_files: () -> Hash[Symbol, Set[Hash[Symbol, untyped]]]
36
+ def self.manifest_files: () -> Hash[Symbol, Array[Hash[Symbol, untyped]]]
31
37
  def self.request_inline_stylesheets: () -> Hash[Symbol, Array[Hash[Symbol, untyped]]]
38
+ def self.request_stylesheet_files: () -> Hash[Symbol, Hash[String, Hash[Symbol, untyped]]]
32
39
  def self.stylesheets_for: (?namespace: Symbol | String | nil) -> Array[Hash[Symbol, untyped]]
33
40
  def self.clear: (?namespace: Symbol | String | nil) -> void
34
41
  def self.clear_manifest: (?namespace: Symbol | String | nil) -> void
35
42
  def self.render_head_stylesheets: (?ActionView::Base | nil view_context, ?namespace: Symbol | String | nil) -> String
43
+ def self.inject_pending_head_stylesheets: (String html, ?ActionView::Base | nil view_context) -> String
44
+ def self.pending_head_stylesheets?: () -> bool
36
45
  def self.any?: (?namespace: Symbol | String | nil) -> bool
37
46
  end
38
47
 
48
+ class HeadInjectionMiddleware
49
+ def initialize: (untyped app) -> void
50
+ def call: (Hash[Symbol, untyped] env) -> [Integer, Hash[String, String], untyped]
51
+ end
52
+
53
+ module ComponentClassMethods
54
+ MAX_CSS_CACHE_ENTRIES: Integer
55
+ def css_cache: () -> Hash[String, String]
56
+ def store_css_cache: (String cache_key, String scoped_css) -> String
57
+ def clear_css_cache: () -> void
58
+ def capsule_id: () -> String | nil
59
+ def capsule_id: (String capsule_id) -> String
60
+ def stylesheet_registry: (?namespace: Symbol | String | nil, ?cache_strategy: Symbol, ?cache_ttl: Integer | ActiveSupport::Duration | nil, ?cache_proc: Proc | nil) -> void
61
+ def style_capsule: (?namespace: Symbol | String | nil, ?cache_strategy: Symbol | String | Proc | nil, ?cache_ttl: Integer | ActiveSupport::Duration | nil, ?cache_proc: Proc | nil, ?scoping_strategy: Symbol | nil, ?head_rendering: bool | nil, ?tag: Symbol | String | nil) -> void
62
+ def head_rendering?: () -> bool
63
+ def stylesheet_namespace: () -> Symbol | String | nil
64
+ def custom_capsule_id: () -> String | nil
65
+ def inline_cache_strategy: () -> Symbol | nil
66
+ def inline_cache_strategy: (Symbol strategy, ?ttl: Integer | nil, ?cache_proc: Proc | nil) -> Symbol
67
+ def inline_cache_ttl: () -> Integer | ActiveSupport::Duration | nil
68
+ def inline_cache_proc: () -> Proc | nil
69
+ def stylesheet_link_options: () -> Hash[untyped, untyped] | nil
70
+ def stylesheet_link_options: (Hash[untyped, untyped] options) -> Hash[untyped, untyped]
71
+ def css_scoping_strategy: () -> Symbol
72
+ end
73
+
39
74
  module Component
40
75
  module ClassMethods
41
- def css_cache: () -> Hash[String, String]
42
- def clear_css_cache: () -> void
43
- def capsule_id: () -> String | nil
44
- def capsule_id: (String capsule_id) -> String
45
- def stylesheet_registry: (?namespace: Symbol | String | nil, ?cache_strategy: Symbol, ?cache_ttl: Integer | ActiveSupport::Duration | nil, ?cache_proc: Proc | nil) -> void
46
- def style_capsule: (?namespace: Symbol | String | nil, ?cache_strategy: Symbol | String | Proc | nil, ?cache_ttl: Integer | ActiveSupport::Duration | nil, ?cache_proc: Proc | nil, ?scoping_strategy: Symbol | nil, ?head_rendering: bool | nil) -> void
47
- def head_rendering?: () -> bool
48
- def stylesheet_namespace: () -> Symbol | String | nil
49
- def custom_capsule_id: () -> String | nil
50
- def inline_cache_strategy: () -> Symbol | nil
51
- def inline_cache_strategy: (Symbol strategy, ?ttl: Integer | nil, ?cache_proc: Proc | nil) -> Symbol
52
- def inline_cache_ttl: () -> Integer | ActiveSupport::Duration | nil
53
- def inline_cache_proc: () -> Proc | nil
54
- def stylesheet_link_options: () -> Hash[untyped, untyped] | nil
55
- def stylesheet_link_options: (Hash[untyped, untyped] options) -> Hash[untyped, untyped]
56
- def css_scoping_strategy: () -> Symbol
76
+ include ComponentClassMethods
57
77
  end
58
78
 
59
79
  def component_capsule: () -> String
@@ -62,22 +82,7 @@ module StyleCapsule
62
82
 
63
83
  module ViewComponent
64
84
  module ClassMethods
65
- def css_cache: () -> Hash[String, String]
66
- def clear_css_cache: () -> void
67
- def capsule_id: () -> String | nil
68
- def capsule_id: (String capsule_id) -> String
69
- def stylesheet_registry: (?namespace: Symbol | String | nil, ?cache_strategy: Symbol, ?cache_ttl: Integer | ActiveSupport::Duration | nil, ?cache_proc: Proc | nil) -> void
70
- def style_capsule: (?namespace: Symbol | String | nil, ?cache_strategy: Symbol | String | Proc | nil, ?cache_ttl: Integer | ActiveSupport::Duration | nil, ?cache_proc: Proc | nil, ?scoping_strategy: Symbol | nil, ?head_rendering: bool | nil) -> void
71
- def head_rendering?: () -> bool
72
- def stylesheet_namespace: () -> Symbol | String | nil
73
- def custom_capsule_id: () -> String | nil
74
- def inline_cache_strategy: () -> Symbol | nil
75
- def inline_cache_strategy: (Symbol strategy, ?ttl: Integer | nil, ?cache_proc: Proc | nil) -> Symbol
76
- def inline_cache_ttl: () -> Integer | ActiveSupport::Duration | nil
77
- def inline_cache_proc: () -> Proc | nil
78
- def stylesheet_link_options: () -> Hash[untyped, untyped] | nil
79
- def stylesheet_link_options: (Hash[untyped, untyped] options) -> Hash[untyped, untyped]
80
- def css_scoping_strategy: () -> Symbol
85
+ include ComponentClassMethods
81
86
  end
82
87
 
83
88
  def component_capsule: () -> String
@@ -92,17 +97,16 @@ module StyleCapsule
92
97
  module Helper
93
98
  def generate_capsule_id: (String css_content) -> String
94
99
  def scope_css: (String css_content, String capsule_id) -> String
95
- def style_capsule: (?String css_content, ?capsule_id: String | nil) { () -> String } -> String
100
+ def style_capsule: (?String css_content, ?capsule_id: String | nil, ?tag: Symbol | String) { () -> String } -> String
96
101
  def register_stylesheet: (String file_path, ?namespace: Symbol | String | nil, **Hash[untyped, untyped] options) -> void
97
102
  def stylesheet_registry_tags: (?namespace: Symbol | String | nil) -> String
98
103
  end
99
104
 
100
105
  module PhlexHelper
101
106
  def register_stylesheet: (String file_path, ?namespace: Symbol | String | nil, **Hash[untyped, untyped] options) -> void
102
- def stylesheet_registry_tags: (?namespace: Symbol | String | nil) -> void
107
+ def stylesheet_registry_tags: (?namespace: Symbol | String | nil) -> String
103
108
  end
104
109
 
105
110
  class Railtie < Rails::Railtie
106
111
  end
107
112
  end
108
-