classlist 0.1.0 → 1.1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -1
- data/README.md +91 -5
- data/lib/classlist/add.rb +20 -0
- data/lib/classlist/all.rb +13 -0
- data/lib/classlist/operation.rb +11 -0
- data/lib/classlist/remove.rb +20 -0
- data/lib/classlist/reset.rb +18 -0
- data/lib/classlist/version.rb +1 -1
- data/lib/classlist.rb +78 -9
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 13b03b38d0d38240cdabd34d10b534b811b5b292eea5c4e43eabd24f5ab199dc
|
4
|
+
data.tar.gz: d83e6fac0aacdb375188e2d5b633bc0a3e7f2f758ef1ff6262ac93ca544b8b5a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 00bff560b1cd9064b353dd1979f0d5644bbe1e861d6ea0d646e4a25cb16c7eb3ae51b66e49bbcf13fb15531065a6b9d5d4818879088ceca8434174bffc082075
|
7
|
+
data.tar.gz: 418764901609311aea4f245cda2d297110a932402a61aa4999f79955e37e4221f8509b6a91a5f86e168ca7cff62c8b1455b8156be3a97b517d4c81ec3ec92311
|
data/CHANGELOG.md
CHANGED
@@ -9,4 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
9
9
|
|
10
10
|
### Added
|
11
11
|
|
12
|
-
-
|
12
|
+
- Support for chains of operations longer than the most simple cases.
|
13
|
+
- Introduce Classlist::Operation as a common super class for Classlist::Add, Classlist::Remove, Classlist::Reset.
|
14
|
+
- Classlist::Add that adds all entries when merged
|
15
|
+
|
16
|
+
## [1.0.0]
|
17
|
+
|
18
|
+
### Added
|
19
|
+
|
20
|
+
- Classlist::Reset that replaces all entries when merged
|
21
|
+
- Classlist::Remove that removes entries when merged
|
22
|
+
- DOMTokenList compatible Classlist class.
|
data/README.md
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
# Classlist
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
TODO: Delete this and the text above, and describe your gem
|
3
|
+
Serverside manipulation of CSS class lists. Works especially well with Tailwind and View Components.
|
6
4
|
|
7
5
|
## Installation
|
8
6
|
|
@@ -10,6 +8,8 @@ Add this line to your application's Gemfile:
|
|
10
8
|
|
11
9
|
```ruby
|
12
10
|
gem 'classlist'
|
11
|
+
# or if you don't want to manually require stuff:
|
12
|
+
gem 'classlist', require: 'classlist/all'
|
13
13
|
```
|
14
14
|
|
15
15
|
And then execute:
|
@@ -22,7 +22,93 @@ Or install it yourself as:
|
|
22
22
|
|
23
23
|
## Usage
|
24
24
|
|
25
|
-
|
25
|
+
Imagine having a component that outputs the following markup when you render it:
|
26
|
+
|
27
|
+
```erb
|
28
|
+
<%= render(CardComponent.new) %>
|
29
|
+
```
|
30
|
+
|
31
|
+
```html
|
32
|
+
<div class="card float-left">...</div>
|
33
|
+
```
|
34
|
+
|
35
|
+
Now you're tasked with implementing a card with another background color. That's easy, you think, I'll just add an option that adds more classes to the component:
|
36
|
+
|
37
|
+
```erb
|
38
|
+
<%= render(CardComponent.new(:classes => "bg-grey")) %>
|
39
|
+
<!-- card.html.erb -->
|
40
|
+
<div class="card float-left <%= classes %>">
|
41
|
+
```
|
42
|
+
|
43
|
+
That works and all is well. But next day the task is to make a card that isn't floated left. You could remove `float-left` from the template and move it to all calls to render:
|
44
|
+
|
45
|
+
```erb
|
46
|
+
<%= render(CardComponent.new(:classes => "float-left bg-grey")) %>
|
47
|
+
<!-- card.html.erb -->
|
48
|
+
<div class="card <%= classes %>">
|
49
|
+
```
|
50
|
+
|
51
|
+
Depending on the number of classes and the number of render calls that could work. But how about if you were able to write
|
52
|
+
|
53
|
+
```erb
|
54
|
+
<%= render(CardComponent.new(:classes => Classlist::Remove.new("float-left"))) %>
|
55
|
+
```
|
56
|
+
|
57
|
+
With Classlist you can:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
# card_component.rb
|
61
|
+
def classes
|
62
|
+
Classlist.new("card float-left") + @classes
|
63
|
+
end
|
64
|
+
```
|
65
|
+
|
66
|
+
```erb
|
67
|
+
<!-- card.html.erb -->
|
68
|
+
<div class="<%= classes %>">
|
69
|
+
```
|
70
|
+
|
71
|
+
The resulting markup will be
|
72
|
+
|
73
|
+
```html
|
74
|
+
<div class="card">
|
75
|
+
```
|
76
|
+
|
77
|
+
because
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
Classlist.new("card float-left") + Classlist::Remove.new("float-left") == Classlist.new("card")
|
81
|
+
```
|
82
|
+
|
83
|
+
### Basic usage
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
# Create a new classlist - these are equivalent:
|
87
|
+
classes = Classlist.new("pt-6 space-y-4")
|
88
|
+
classes = Classlist.new(["pt-6", "space-y-4"])
|
89
|
+
|
90
|
+
# Add classes
|
91
|
+
classes.add("md:p-8 text-center")
|
92
|
+
classes.to_s #=> "pt-6 space-y-4 md:p-8 text-center"
|
93
|
+
|
94
|
+
# Remove classes
|
95
|
+
classes.remove("md:p-8")
|
96
|
+
classes.to_s #=> "pt-6 space-y-4 text-center"
|
97
|
+
|
98
|
+
# Toggle classes
|
99
|
+
classes.toggle("hidden")
|
100
|
+
classes.to_s #=> "pt-6 space-y-4 text-center hidden"
|
101
|
+
classes.toggle("text-center")
|
102
|
+
classes.to_s #=> "pt-6 space-y-4 hidden"
|
103
|
+
|
104
|
+
# Replace classes
|
105
|
+
classes.replace("hidden", "block")
|
106
|
+
classes.to_s #=> "pt-6 space-y-4 block"
|
107
|
+
```
|
108
|
+
|
109
|
+
## DOM compatibility
|
110
|
+
|
111
|
+
While Classlist aims to be a feature-compatible version of [`DOMTokenList`](https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList) that doesn't always make for particularily Ruby'esque methods. In cases where Ruby has similar methods named differently than the DOM, we'll prefer Ruby-style method names while keeping aliases with the names from `DOMTokenList`.
|
26
112
|
|
27
113
|
## Development
|
28
114
|
|
@@ -32,4 +118,4 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
32
118
|
|
33
119
|
## Contributing
|
34
120
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
121
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/substancelab/classlist.
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "classlist/operation"
|
4
|
+
|
5
|
+
# Classlist::Add is an operation that adds tokens to the original
|
6
|
+
# classlist when added to it.
|
7
|
+
class Classlist::Add < Classlist::Operation
|
8
|
+
def merge(original)
|
9
|
+
original.entries + entries
|
10
|
+
end
|
11
|
+
|
12
|
+
# resolve changes the original classlist
|
13
|
+
def resolve(original)
|
14
|
+
entries.each do |entry|
|
15
|
+
original.add(entry)
|
16
|
+
end
|
17
|
+
|
18
|
+
super
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Require this file to load all of Classlist into your application.
|
4
|
+
#
|
5
|
+
# For example in a Gemfile:
|
6
|
+
#
|
7
|
+
# gem "classlist", require: "classlist/all"
|
8
|
+
#
|
9
|
+
# Or you can just require what you need manually.
|
10
|
+
|
11
|
+
require "classlist/add"
|
12
|
+
require "classlist/remove"
|
13
|
+
require "classlist/reset"
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "classlist"
|
4
|
+
|
5
|
+
# Classlist::Operations modify the original classlist
|
6
|
+
class Classlist::Operation < Classlist
|
7
|
+
# resolve changes the original classlist
|
8
|
+
def resolve(original_classlist)
|
9
|
+
resolve_operations(original_classlist)
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "classlist/operation"
|
4
|
+
|
5
|
+
# Classlist::Remove is an operation that removes tokens from the original
|
6
|
+
# classlist when added to it.
|
7
|
+
class Classlist::Remove < Classlist::Operation
|
8
|
+
def merge(original)
|
9
|
+
original.entries - entries
|
10
|
+
end
|
11
|
+
|
12
|
+
# #resolve changes the original classlist
|
13
|
+
def resolve(original)
|
14
|
+
entries.each do |entry|
|
15
|
+
original.remove(entry)
|
16
|
+
end
|
17
|
+
|
18
|
+
super
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "classlist/operation"
|
4
|
+
|
5
|
+
# Classlist::Reset is an operation that removes all tokens from the original
|
6
|
+
# classlist when merged.
|
7
|
+
class Classlist::Reset < Classlist::Operation
|
8
|
+
def merge(original)
|
9
|
+
original.entries.replace(entries)
|
10
|
+
end
|
11
|
+
|
12
|
+
# #resolve changes the original classlist
|
13
|
+
def resolve(original)
|
14
|
+
original.entries.replace(entries)
|
15
|
+
|
16
|
+
super
|
17
|
+
end
|
18
|
+
end
|
data/lib/classlist/version.rb
CHANGED
data/lib/classlist.rb
CHANGED
@@ -1,11 +1,42 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "forwardable"
|
4
|
+
|
3
5
|
require_relative "classlist/version"
|
4
6
|
|
5
7
|
class Classlist
|
8
|
+
class ArgumentError < ::ArgumentError; end
|
9
|
+
|
6
10
|
class Error < StandardError; end
|
7
11
|
|
8
|
-
|
12
|
+
extend Forwardable
|
13
|
+
def_delegators :@entries, :each
|
14
|
+
|
15
|
+
attr_reader :entries, :operations
|
16
|
+
|
17
|
+
# Returns the Classlist resulting from adding other to this classlist.
|
18
|
+
def +(other)
|
19
|
+
case other
|
20
|
+
when Classlist::Operation
|
21
|
+
add_operation(other)
|
22
|
+
self
|
23
|
+
when Classlist
|
24
|
+
result = other.merge(self)
|
25
|
+
Classlist.new(result)
|
26
|
+
else
|
27
|
+
result = entries + build_entries(other)
|
28
|
+
Classlist.new(result)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def ==(other)
|
33
|
+
return false unless other.is_a?(self.class)
|
34
|
+
|
35
|
+
resolve_operations(self)
|
36
|
+
other.resolve_operations
|
37
|
+
|
38
|
+
@entries == other.entries
|
39
|
+
end
|
9
40
|
|
10
41
|
# Adds the given tokens to the list, omitting any that are already present.
|
11
42
|
def add(tokens)
|
@@ -15,8 +46,36 @@ class Classlist
|
|
15
46
|
end
|
16
47
|
end
|
17
48
|
|
49
|
+
def add_operation(other)
|
50
|
+
@operations << other
|
51
|
+
end
|
52
|
+
|
53
|
+
def include?(token)
|
54
|
+
entries.include?(token)
|
55
|
+
end
|
56
|
+
alias_method :contains, :include?
|
57
|
+
|
18
58
|
def initialize(entries = [])
|
19
59
|
@entries = build_entries(entries)
|
60
|
+
@operations = []
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns the item in the list by its index, or null if the index is greater
|
64
|
+
# than or equal to the list's length.
|
65
|
+
def item(index)
|
66
|
+
return nil if index.negative?
|
67
|
+
|
68
|
+
entries[index]
|
69
|
+
end
|
70
|
+
|
71
|
+
# An integer representing the number of objects stored in the object.
|
72
|
+
def length
|
73
|
+
entries.length
|
74
|
+
end
|
75
|
+
|
76
|
+
# Returns a list of tokens in this classlist merged with the given classlist.
|
77
|
+
def merge(classlist)
|
78
|
+
(classlist.entries + entries).uniq
|
20
79
|
end
|
21
80
|
|
22
81
|
# Removes the specified tokens from the classlist, ignoring any that are not
|
@@ -32,10 +91,10 @@ class Classlist
|
|
32
91
|
# exist, #replace returns false immediately, without adding the new token to
|
33
92
|
# the token list.
|
34
93
|
def replace(old_token, new_token)
|
35
|
-
return false unless
|
94
|
+
return false unless include?(old_token)
|
36
95
|
|
37
|
-
if
|
38
|
-
|
96
|
+
if include?(new_token)
|
97
|
+
remove(old_token)
|
39
98
|
else
|
40
99
|
index = entries.index(old_token)
|
41
100
|
entries[index] = new_token
|
@@ -44,13 +103,21 @@ class Classlist
|
|
44
103
|
true
|
45
104
|
end
|
46
105
|
|
106
|
+
def resolve_operations(original_classlist = self)
|
107
|
+
operations.each do |operation|
|
108
|
+
operation.resolve(original_classlist)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
47
112
|
def to_a
|
48
|
-
|
113
|
+
resolve_operations(self)
|
114
|
+
@entries
|
49
115
|
end
|
50
116
|
|
51
117
|
def to_s
|
52
|
-
|
118
|
+
to_a.join(" ")
|
53
119
|
end
|
120
|
+
alias_method :value, :to_s
|
54
121
|
|
55
122
|
# Removes an existing token from the list and returns false. If the token
|
56
123
|
# doesn't exist it's added and the function returns true.
|
@@ -59,11 +126,13 @@ class Classlist
|
|
59
126
|
# set to false, then token will only be removed, but not added. If set to
|
60
127
|
# true, then token will only be added, but not removed.
|
61
128
|
def toggle(token, force = nil)
|
129
|
+
raise ArgumentError, "The token can not contain whitespace." if token.to_s.include?(" ")
|
130
|
+
|
62
131
|
if entries.include?(token)
|
63
|
-
|
132
|
+
remove(token) unless force == true
|
64
133
|
result = false
|
65
134
|
else
|
66
|
-
|
135
|
+
add(token) unless force == false
|
67
136
|
result = true
|
68
137
|
end
|
69
138
|
|
@@ -90,6 +159,6 @@ class Classlist
|
|
90
159
|
entries.split(" ")
|
91
160
|
else
|
92
161
|
raise Error, "Invalid entries: #{entries.inspect}"
|
93
|
-
end
|
162
|
+
end.uniq
|
94
163
|
end
|
95
164
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: classlist
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jakob Skjerning
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-11-07 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Serverside manipulation of lists of CSS classnames that play nicely with
|
14
14
|
View Components.
|
@@ -28,6 +28,11 @@ files:
|
|
28
28
|
- bin/setup
|
29
29
|
- classlist.gemspec
|
30
30
|
- lib/classlist.rb
|
31
|
+
- lib/classlist/add.rb
|
32
|
+
- lib/classlist/all.rb
|
33
|
+
- lib/classlist/operation.rb
|
34
|
+
- lib/classlist/remove.rb
|
35
|
+
- lib/classlist/reset.rb
|
31
36
|
- lib/classlist/version.rb
|
32
37
|
- sig/classlist.rbs
|
33
38
|
homepage: https://github.com/substancelab/classlist
|