view_component-contrib 0.2.0 → 0.2.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 814046bee78131bac6659eaa62160b6dfef169d48d1c5850c03dbe6a00a2ad0f
4
- data.tar.gz: ef1ec7cfb3f71bf4db995be3a564dcfc0ff04e72d3c4e116515d216de18b38e8
3
+ metadata.gz: eb40fc2b6095e17a5cb7402bb9c577ee9df9152b65342a3fd2879861b0ec61c4
4
+ data.tar.gz: da852768b8dfe7907aae80bcee8afb5a52998185365e4f2bf702d2e5160df8cf
5
5
  SHA512:
6
- metadata.gz: 9a5d578dfc44e7318da343a0aefe65946cce2399675d92646fd33db8e7494040d16433a3c409a08185d04c249fbc538e494175dce593a6bde19e27d254926d42
7
- data.tar.gz: d01e0bf7f11d866aaab42dafb040e7ee45e4257524888b7bb6768b399d2db03c971867e6b14d839c1a66f7e37d9fe71982e287c8280b3a16811891bc61ee4723
6
+ metadata.gz: d8492733e339fe678625730a079a5831c3647f9063aa13f50f3ef34d1a4c03a1505c536f06bb9cf3959310e311774b265c18cb9f01070d77b3d93a0e7b295241
7
+ data.tar.gz: d6e0426d3014ea7978eaf807e9a8aa11b0d729f16309e303c2a6a2d0d2d09d34d9e2146293648b57aba7bece138c831f4182c983aea4c2602dfa3dcc769f0cf3
data/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.2.2 (2023-11-29)
6
+
7
+ - Add `compound` styles support. ([@palkan][])
8
+
9
+ - Support using booleans as style variant values. ([@palkan][])
10
+
11
+ ## 0.2.1 (2023-11-16)
12
+
13
+ - Fix style variants inhertiance. ([@palkan][])
14
+
5
15
  ## 0.2.0 (2023-11-07)
6
16
 
7
17
  - Introduce style variants. ([@palkan][])
data/README.md CHANGED
@@ -209,15 +209,19 @@ class ButtonComponent < ViewComponent::Base
209
209
  md { "text-base" }
210
210
  lg { "px-4 py-3 text-lg" }
211
211
  }
212
+ disabled {
213
+ yes { "opacity-75" }
214
+ }
212
215
  }
213
216
  defaults { {size: :md, color: :primary} }
214
217
  end
215
218
 
216
- attr_reader :size, :color
219
+ attr_reader :size, :color, :disabled
217
220
 
218
- def initialize(size: nil, color: nil)
221
+ def initialize(size: nil, color: nil, disabled: false)
219
222
  @size = size
220
223
  @color = color
224
+ @disabled = disabled
221
225
  end
222
226
  end
223
227
  ```
@@ -234,6 +238,12 @@ Passing `size: :lg` and `color: :secondary` would result in the following HTML:
234
238
  <button class="font-medium bg-purple-500 text-white rounded-full px-4 py-3 text-lg">Click me</button>
235
239
  ```
236
240
 
241
+ The `true` / `false` variant value would be converted into the `yes` / `no` variants:
242
+
243
+ ```erb
244
+ <button class="<%= style(size:, color:, disabled: true) %>">Click me</button>
245
+ ```
246
+
237
247
  **NOTE:** If you pass `nil`, the default value would be used.
238
248
 
239
249
  You can define multiple style sets in a single component:
@@ -276,11 +286,74 @@ class ButtonComponent < ViewComponent::Base
276
286
  # You can provide either a proc or any other callable object
277
287
  style_config.postprocess_with do |classes|
278
288
  # classes is an array of CSS classes
289
+ # NOTE: This is an abstract TailwindMerge class, not to be confused with existing libraries
279
290
  TailwindMerge.call(classes).join(" ")
280
291
  end
281
292
  end
282
293
  ```
283
294
 
295
+ ### Dependent (or compound) styles
296
+
297
+ Sometimes it might be necessary to define complex styling rules, e.g., when a combination of variants requires adding additional styles. That's where usage of Ruby blocks for configuration becomes useful. For example:
298
+
299
+ ```ruby
300
+ style do
301
+ variants {
302
+ size {
303
+ sm { "text-sm" }
304
+ md { "text-base" }
305
+ lg { "px-4 py-3 text-lg" }
306
+ }
307
+ theme {
308
+ primary do |size:, **|
309
+ %w[bg-blue-500 text-white].tap do
310
+ _1 << "uppercase" if size == :lg
311
+ end
312
+ end
313
+ secondary { %w[bg-purple-500 text-white] }
314
+ }
315
+ }
316
+ end
317
+ ```
318
+
319
+ The specified variants are passed as block arguments, so you can implement dynamic styling.
320
+
321
+ If you prefer declarative approach, you can use the special `compound` directive. The previous example could be rewritten as follows:
322
+
323
+ ```ruby
324
+ style do
325
+ variants {
326
+ size {
327
+ sm { "text-sm" }
328
+ md { "text-base" }
329
+ lg { "px-4 py-3 text-lg" }
330
+ }
331
+ theme {
332
+ primary { %w[bg-blue-500 text-white] }
333
+ secondary { %w[bg-purple-500 text-white] }
334
+ }
335
+ }
336
+
337
+ compound(size: :lg, theme: :primary) { %w[uppercase] }
338
+ end
339
+ ```
340
+
341
+ ### Using with TailwindCSS LSP
342
+
343
+ To make completions (and other LSP features) work with our DSL, try the following configuration:
344
+
345
+ ```json
346
+ "tailwindCSS.includeLanguages": {
347
+ "erb": "html",
348
+ "ruby": "html"
349
+ },
350
+ "tailwindCSS.experimental.classRegex": [
351
+ "%w\\[([^\\]]*)\\]"
352
+ ]
353
+ ```
354
+
355
+ **NOTE:** It will only work with `%w[ ... ]` word arrays, but you can adjust it to your needs.
356
+
284
357
  ## Organizing assets (JS, CSS)
285
358
 
286
359
  **NOTE**: This section assumes the usage of Vite or Webpack. See [this discussion](https://github.com/palkan/view_component-contrib/discussions/14) for other options.
@@ -75,6 +75,7 @@ module ViewComponentContrib
75
75
  @base_block = nil
76
76
  @defaults = {}
77
77
  @variants = {}
78
+ @compounds = {}
78
79
 
79
80
  instance_eval(&init_block) if init_block
80
81
  end
@@ -91,17 +92,50 @@ module ViewComponentContrib
91
92
  @variants = VariantBuilder.new(true).build(&block)
92
93
  end
93
94
 
95
+ def compound(**variants, &block)
96
+ @compounds[variants] = block
97
+ end
98
+
94
99
  def compile(**variants)
95
100
  acc = Array(@base_block&.call || [])
96
101
 
97
- @defaults.merge(variants.compact).each do |variant, value|
102
+ config = @defaults.merge(variants.compact)
103
+
104
+ config.each do |variant, value|
105
+ value = cast_value(value)
98
106
  variant = @variants.dig(variant, value) || next
99
- styles = variant.is_a?(::Proc) ? variant.call : variant
107
+ styles = variant.is_a?(::Proc) ? variant.call(**config) : variant
108
+ acc.concat(Array(styles))
109
+ end
110
+
111
+ @compounds.each do |compound, value|
112
+ next unless compound.all? { |k, v| config[k] == v }
113
+
114
+ styles = value.is_a?(::Proc) ? value.call(**config) : value
100
115
  acc.concat(Array(styles))
101
116
  end
102
117
 
103
118
  acc
104
119
  end
120
+
121
+ def dup
122
+ copy = super
123
+ copy.instance_variable_set(:@defaults, @defaults.dup)
124
+ copy.instance_variable_set(:@variants, @variants.dup)
125
+ copy.instance_variable_set(:@compounds, @compounds.dup)
126
+ copy
127
+ end
128
+
129
+ private
130
+
131
+ def cast_value(val)
132
+ case val
133
+ when true then :yes
134
+ when false then :no
135
+ else
136
+ val
137
+ end
138
+ end
105
139
  end
106
140
 
107
141
  class StyleConfig # :nodoc:
@@ -131,6 +165,12 @@ module ViewComponentContrib
131
165
  @postprocessor = callable || block
132
166
  end
133
167
 
168
+ def dup
169
+ copy = super
170
+ copy.instance_variable_set(:@styles, @styles.dup)
171
+ copy
172
+ end
173
+
134
174
  private
135
175
 
136
176
  attr_reader :styles
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ViewComponentContrib # :nodoc:all
4
- VERSION = "0.2.0"
4
+ VERSION = "0.2.2"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: view_component-contrib
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vladimir Dementyev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-08 00:00:00.000000000 Z
11
+ date: 2023-11-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: view_component