class_variants 1.0.0 → 1.1.1
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 +4 -4
- data/LICENSE +1 -1
- data/lib/class_variants/action_view/helpers.rb +4 -2
- data/lib/class_variants/configuration.rb +2 -0
- data/lib/class_variants/helper.rb +13 -8
- data/lib/class_variants/instance.rb +51 -17
- data/lib/class_variants/railtie.rb +2 -0
- data/lib/class_variants/version.rb +3 -1
- data/lib/class_variants.rb +2 -0
- data/lib/generators/class_variants/install/install_generator.rb +2 -0
- data/readme.md +66 -26
- metadata +3 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b8ecbdedc158b731b446bf166b1dcc6d99b4569cc90f484e95ff6c5466cc3db9
|
|
4
|
+
data.tar.gz: 80de309d4e820f9a3b5667f8c8b4958172906971e923beb3fd169a915cb20811
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3fda53be42ac74e51fb85209a24d3bbfed78101052c4bcf016f307f5c0e852adfaf1062102f5e7a80d5563c101c1e418b836eb274557fee1655679084dafe9b8
|
|
7
|
+
data.tar.gz: c20bcba0b71ea4b7c151e2e9a07ca6eac7508f4d938cf8c4b0923baea4dd934651582f4ba7a9eaf0fdacaa606ad71db1faff4ac31705237ca7b5fe5bd31bf26d
|
data/LICENSE
CHANGED
|
@@ -1,23 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module ClassVariants
|
|
2
4
|
module Helper
|
|
3
5
|
module ClassMethods
|
|
4
6
|
def class_variants(...)
|
|
5
|
-
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
def _class_variants_instance
|
|
9
|
-
@_class_variants_instance
|
|
7
|
+
singleton_class.instance_variable_get(:@_class_variants_instance).merge(...)
|
|
10
8
|
end
|
|
11
9
|
end
|
|
12
10
|
|
|
13
11
|
def self.included(base)
|
|
14
12
|
base.extend(ClassMethods)
|
|
13
|
+
base.singleton_class.instance_variable_set(:@_class_variants_instance, ClassVariants::Instance.new)
|
|
14
|
+
|
|
15
|
+
def base.inherited(subclass)
|
|
16
|
+
super if defined?(super)
|
|
17
|
+
|
|
18
|
+
subclass.singleton_class.instance_variable_set(
|
|
19
|
+
:@_class_variants_instance, singleton_class.instance_variable_get(:@_class_variants_instance).dup
|
|
20
|
+
)
|
|
21
|
+
end
|
|
15
22
|
end
|
|
16
23
|
|
|
17
24
|
def class_variants(...)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
self.class._class_variants_instance.render(...)
|
|
25
|
+
self.class.singleton_class.instance_variable_get(:@_class_variants_instance).render(...)
|
|
21
26
|
end
|
|
22
27
|
end
|
|
23
28
|
end
|
|
@@ -1,20 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module ClassVariants
|
|
2
4
|
class Instance
|
|
3
|
-
def initialize(
|
|
4
|
-
|
|
5
|
+
def initialize(...)
|
|
6
|
+
@bases = []
|
|
7
|
+
@variants = []
|
|
8
|
+
@defaults = {}
|
|
9
|
+
@slots = nil
|
|
5
10
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
@defaults = options.fetch(:defaults, {})
|
|
11
|
+
merge(...)
|
|
12
|
+
end
|
|
9
13
|
|
|
10
|
-
|
|
14
|
+
def dup
|
|
15
|
+
self.class.new.tap do |copy|
|
|
16
|
+
copy.instance_variable_set(:@bases, @bases.dup)
|
|
17
|
+
copy.instance_variable_set(:@variants, @variants.dup)
|
|
18
|
+
copy.instance_variable_set(:@defaults, @defaults.dup)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def merge(**options, &block)
|
|
23
|
+
raise ArgumentError, "Use of hash config and code block is not supported" if !options.empty? && block
|
|
24
|
+
|
|
25
|
+
(base = options.fetch(:base, nil)) && @bases << {class: base, slot: :default}
|
|
26
|
+
@variants += [
|
|
27
|
+
expand_variants(options.fetch(:variants, {})),
|
|
28
|
+
expand_compound_variants(options.fetch(:compound_variants, []))
|
|
29
|
+
].inject(:+)
|
|
30
|
+
@defaults.merge!(options.fetch(:defaults, {}))
|
|
31
|
+
|
|
32
|
+
instance_eval(&block) if block
|
|
33
|
+
|
|
34
|
+
self
|
|
11
35
|
end
|
|
12
36
|
|
|
13
37
|
def render(slot = :default, **overrides)
|
|
14
38
|
classes = overrides.delete(:class)
|
|
39
|
+
result = []
|
|
15
40
|
|
|
16
41
|
# Start with our default classes
|
|
17
|
-
|
|
42
|
+
@bases.each do |base|
|
|
43
|
+
result << base[:class] if base[:slot] == slot
|
|
44
|
+
end
|
|
18
45
|
|
|
19
46
|
# Then merge the passed in overrides on top of the defaults
|
|
20
47
|
criteria = @defaults.merge(overrides)
|
|
@@ -22,9 +49,15 @@ module ClassVariants
|
|
|
22
49
|
@variants.each do |candidate|
|
|
23
50
|
next unless candidate[:slot] == slot
|
|
24
51
|
|
|
25
|
-
|
|
26
|
-
|
|
52
|
+
match = false
|
|
53
|
+
|
|
54
|
+
candidate.each_key do |key|
|
|
55
|
+
next if key == :class || key == :slot
|
|
56
|
+
match = criteria[key] == candidate[key]
|
|
57
|
+
break unless match
|
|
27
58
|
end
|
|
59
|
+
|
|
60
|
+
result << candidate[:class] if match
|
|
28
61
|
end
|
|
29
62
|
|
|
30
63
|
# add the passed in classes to the result
|
|
@@ -40,21 +73,21 @@ module ClassVariants
|
|
|
40
73
|
private
|
|
41
74
|
|
|
42
75
|
def base(klass = nil, &block)
|
|
43
|
-
raise ArgumentError, "Use of positional argument and code block is not supported" if klass &&
|
|
76
|
+
raise ArgumentError, "Use of positional argument and code block is not supported" if klass && block
|
|
44
77
|
|
|
45
|
-
if
|
|
78
|
+
if block
|
|
46
79
|
with_slots(&block).each do |slot|
|
|
47
|
-
@
|
|
80
|
+
@bases << slot
|
|
48
81
|
end
|
|
49
82
|
else
|
|
50
|
-
@
|
|
83
|
+
@bases << {slot: :default, class: klass}
|
|
51
84
|
end
|
|
52
85
|
end
|
|
53
86
|
|
|
54
87
|
def variant(**options, &block)
|
|
55
|
-
raise ArgumentError, "Use of class option and code block is not supported" if options.key?(:class) &&
|
|
88
|
+
raise ArgumentError, "Use of class option and code block is not supported" if options.key?(:class) && block
|
|
56
89
|
|
|
57
|
-
if
|
|
90
|
+
if block
|
|
58
91
|
with_slots(&block).each do |slot|
|
|
59
92
|
@variants << options.merge(slot)
|
|
60
93
|
end
|
|
@@ -74,9 +107,10 @@ module ClassVariants
|
|
|
74
107
|
end
|
|
75
108
|
|
|
76
109
|
def with_slots
|
|
77
|
-
|
|
110
|
+
new_slots = []
|
|
111
|
+
@slots = new_slots
|
|
78
112
|
yield
|
|
79
|
-
|
|
113
|
+
new_slots
|
|
80
114
|
end
|
|
81
115
|
|
|
82
116
|
def expand_variants(variants)
|
data/lib/class_variants.rb
CHANGED
data/readme.md
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
We ❤️ Tailwind CSS but sometimes it's difficult to manage the state of some elements using conditionals. `class_variants` is a tiny helper that should enable you to create, configure, and apply different variants of elements as classes.
|
|
4
4
|
|
|
5
|
+

|
|
6
|
+
|
|
5
7
|
Inspired by [variant-classnames](https://github.com/mattvalleycodes/variant-classnames) ✌️
|
|
6
8
|
|
|
7
9
|
## Quicklinks
|
|
8
10
|
|
|
9
11
|
* [DRY up your tailwind CSS using this awesome gem](https://www.youtube.com/watch?v=cFcwNH6x77g)
|
|
10
12
|
|
|
11
|
-
|
|
12
13
|
## Installation
|
|
13
14
|
|
|
14
15
|
Add this line to your application's Gemfile:
|
|
@@ -34,9 +35,9 @@ $ gem install class_variants
|
|
|
34
35
|
We create an object from the class or helper where we define the configuration using four arguments:
|
|
35
36
|
|
|
36
37
|
1. The `base` keyword argument with default classes that should be applied to each variant.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
2. The `variants` keyword argument where we declare the variants with their option and classes.
|
|
39
|
+
3. The `compound_variants` keyword argument where we declare the compound variants with their conditions and classes
|
|
40
|
+
4. The `defaults` keyword argument (optional) where we declare the default value for each variant.
|
|
40
41
|
|
|
41
42
|
Below we'll implement the [button component](https://tailwindui.com/components/application-ui/elements/buttons) from Tailwind UI.
|
|
42
43
|
|
|
@@ -99,7 +100,7 @@ button_classes = ClassVariants.build(
|
|
|
99
100
|
)
|
|
100
101
|
|
|
101
102
|
button_classes.render(color: :red) # => "inline-flex items-center rounded bg-red-600"
|
|
102
|
-
button_classes.render(color: :red, border: true) # => "inline-flex items-center rounded bg-red-600 border border-red-
|
|
103
|
+
button_classes.render(color: :red, border: true) # => "inline-flex items-center rounded bg-red-600 border border-red-800"
|
|
103
104
|
```
|
|
104
105
|
|
|
105
106
|
## Override classes with `render`
|
|
@@ -185,6 +186,14 @@ end
|
|
|
185
186
|
</div>
|
|
186
187
|
```
|
|
187
188
|
|
|
189
|
+
## Merge definitions
|
|
190
|
+
|
|
191
|
+
```ruby
|
|
192
|
+
alert_classes = ClassVariants.build(base: "bg-white")
|
|
193
|
+
alert_classes.merge(base: "text-black")
|
|
194
|
+
alert_classes.render # => "bg-white text-black"
|
|
195
|
+
```
|
|
196
|
+
|
|
188
197
|
## Full API
|
|
189
198
|
|
|
190
199
|
```ruby
|
|
@@ -272,7 +281,7 @@ alert_classes.render(:body, class: "...")
|
|
|
272
281
|
|
|
273
282
|
```ruby
|
|
274
283
|
# Somewhere in your helpers
|
|
275
|
-
def button_classes
|
|
284
|
+
def button_classes
|
|
276
285
|
class_variants(
|
|
277
286
|
base: "inline-flex items-center rounded border border-transparent font-medium text-white hover:text-white shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-2",
|
|
278
287
|
variants: {
|
|
@@ -303,6 +312,10 @@ end
|
|
|
303
312
|
<%= link_to :Avo, "https://avohq.io", class: button_classes.render(color: :red, size: :xl) %>
|
|
304
313
|
```
|
|
305
314
|
|
|
315
|
+
### Output
|
|
316
|
+
|
|
317
|
+
### 
|
|
318
|
+
|
|
306
319
|
## Helper module
|
|
307
320
|
|
|
308
321
|
If you're developing something more complex you might want to use composition more. You might want to use the helper module for that.
|
|
@@ -311,54 +324,81 @@ If you're developing something more complex you might want to use composition mo
|
|
|
311
324
|
class MyClass
|
|
312
325
|
include ClassVariants::Helper
|
|
313
326
|
|
|
314
|
-
class_variants
|
|
315
|
-
base:
|
|
316
|
-
variants: {
|
|
317
|
-
|
|
327
|
+
class_variants(
|
|
328
|
+
base: "bg-white",
|
|
329
|
+
variants: {
|
|
330
|
+
color: {
|
|
331
|
+
red: "text-red",
|
|
332
|
+
blue: "text-blue"
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
)
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
MyClass.new.class_variants(color: :red, class: "shadow") # => "bg-white text-red shadow"
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
This helper supports class inheritance, so that the subclass receives a copy of the class_variants config that the parent class had at the time of inheritance. From that point on, the settings are kept separate for both. Successive calls to class_variants helper method, will cause the configuration to be merged.
|
|
342
|
+
|
|
343
|
+
```ruby
|
|
344
|
+
class A
|
|
345
|
+
include ClassVariants::Helper
|
|
346
|
+
|
|
347
|
+
class_variants(base: "bg-red")
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
class B < A
|
|
351
|
+
class_variants(base: "text-black")
|
|
318
352
|
end
|
|
319
353
|
|
|
320
|
-
|
|
354
|
+
A.class_variants(base: "text-white")
|
|
355
|
+
|
|
356
|
+
A.new.class_variants # => "bg-red text-white"
|
|
357
|
+
B.new.class_variants # => "bg-red text-black"
|
|
321
358
|
```
|
|
322
359
|
|
|
323
360
|
## `tailwind_merge`
|
|
324
361
|
|
|
325
362
|
By default, the classes are merged using `concat`, but you can use the awesome [TailwindMerge](https://github.com/gjtorikian/tailwind_merge) gem.
|
|
326
|
-
Install the gem using `bundle add tailwind_merge` and use this configuration to enable it.
|
|
363
|
+
Install the gem using `bundle add tailwind_merge` and use this configuration to enable it. If you're using Rails, you can put this in an initializer.
|
|
327
364
|
|
|
328
365
|
```ruby
|
|
329
366
|
ClassVariants.configure do |config|
|
|
367
|
+
merger = TailwindMerge::Merger.new
|
|
330
368
|
config.process_classes_with do |classes|
|
|
331
|
-
|
|
369
|
+
merger.merge(classes)
|
|
332
370
|
end
|
|
333
371
|
end
|
|
334
372
|
```
|
|
335
373
|
|
|
336
|
-
### Output
|
|
337
|
-
|
|
338
|
-

|
|
339
|
-
|
|
340
374
|
## Other packages
|
|
341
375
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
376
|
+
- [`active_storage-blurhash`](https://github.com/avo-hq/active_storage-blurhash) - A plug-n-play [blurhash](https://blurha.sh/) integration for images stored in ActiveStorage
|
|
377
|
+
- [`avo`](https://github.com/avo-hq/avo) - Build internal tools, admin panels, and dashboards with Ruby on Rails
|
|
378
|
+
- [`marksmith`](https://github.com/avo-hq/marksmith) - GitHub-style markdown editor for Ruby and Rails
|
|
379
|
+
- [`prop_initializer`](https://github.com/avo-hq/prop_initializer) - A flexible tool for defining properties on Ruby classes.
|
|
380
|
+
- [`stimulus-confetti`](https://github.com/avo-hq/stimulus-confetti) - The easiest way to add confetti to your StimulusJS app
|
|
346
381
|
|
|
347
382
|
## Try Avo ⭐️
|
|
348
383
|
|
|
349
384
|
If you enjoyed this gem try out [Avo](https://github.com/avo-hq/avo). It helps developers build Internal Tools, Admin Panels, CMSes, CRMs, and any other type of Business Apps 10x faster on top of Ruby on Rails.
|
|
350
385
|
|
|
351
|
-
[](https://github.com/avo-hq/avo)
|
|
387
|
+
|
|
388
|
+
## Articles
|
|
389
|
+
|
|
390
|
+
[TIL: How to use `class_variants` with Phlex](https://henrikbjorn.medium.com/til-how-to-use-class-variants-with-phlex-8042bd4407f1)
|
|
352
391
|
|
|
353
392
|
## Contributing
|
|
354
393
|
|
|
355
394
|
1. Fork it `git clone https://github.com/avo-hq/class_variants`
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
395
|
+
2. Create your feature branch `git checkout -b my-new-feature`
|
|
396
|
+
3. Commit your changes `git commit -am 'Add some feature'`
|
|
397
|
+
4. Push to the branch `git push origin my-new-feature`
|
|
398
|
+
5. Create new Pull Request
|
|
360
399
|
|
|
361
400
|
## License
|
|
401
|
+
|
|
362
402
|
This package is available as open source under the terms of the MIT License.
|
|
363
403
|
|
|
364
404
|
## Cutting a release
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: class_variants
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Adrian Marin
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies: []
|
|
13
12
|
description: Easily configure styles and apply them as classes.
|
|
14
13
|
email: adrian@adrianthedev.com
|
|
@@ -36,7 +35,6 @@ metadata:
|
|
|
36
35
|
source_code_uri: https://github.com/avo-hq/class_variants
|
|
37
36
|
bug_tracker_uri: https://github.com/avo-hq/class_variants/issues
|
|
38
37
|
changelog_uri: https://github.com/avo-hq/class_variants/releases
|
|
39
|
-
post_install_message:
|
|
40
38
|
rdoc_options: []
|
|
41
39
|
require_paths:
|
|
42
40
|
- lib
|
|
@@ -51,8 +49,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
51
49
|
- !ruby/object:Gem::Version
|
|
52
50
|
version: '0'
|
|
53
51
|
requirements: []
|
|
54
|
-
rubygems_version: 3.
|
|
55
|
-
signing_key:
|
|
52
|
+
rubygems_version: 3.6.9
|
|
56
53
|
specification_version: 4
|
|
57
54
|
summary: Easily configure styles and apply them as classes.
|
|
58
55
|
test_files: []
|