daisyui 2.2.0 → 2.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: b1bf5647c845ed4fbdf7d538e4934c7171b23039cbc9029d8c68330b82f0acd2
4
- data.tar.gz: 9282c494a1db396b4153fda3c9696040e8c95ac7d495d0bbcf9a0be983a49fb1
3
+ metadata.gz: a83f4b0512262bb7ae533a4c76e09badf6a1f6d9504429dc6cc3febbf163d034
4
+ data.tar.gz: 86bc9c1f0751a6fd58dd64c172202c2d0f87cc7af7f95d46d7a9c8c8dd888d26
5
5
  SHA512:
6
- metadata.gz: f2fa7469a01b18c4bb28110ab4da1238ce8c846fef910e3edc488d283ed641e8cee5fb3b2fb69ca528f643283a1339114db14354a0f3d0d306b67f996923e4d8
7
- data.tar.gz: 282f9add88cc7e82eabd013b81bb4e1470c8809f6687ada460470ef97a472d228182154f644c56a7df000f4714dd8d51eca4bbc5692f5ddbbdba7607e84617f4
6
+ metadata.gz: c1c0df513bd19ed59577cc986f6f10ae48c4c3269097e58077c75addcfa3714296e00347232a044b838e69a98c8c02b0f03a5b7e7a8216a1ef92629292b0b95a
7
+ data.tar.gz: f8ee5ef84355d080506310783167fb64cf19d4c9875eb5082862b2d2240f79575a1cc84c685ff6cd8630f192a8d75a8d3ac65ca49ef8cf0c20d4a176669c9cd7
data/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [2.2.2] - 2026-10-27
4
+
5
+ ### Fixed
6
+
7
+ - A variant member's classes no longer knock each other out. A group now holds
8
+ only the component's own `<component_class>-*` classes; a member's other
9
+ classes Tailwind does not classify (plugin utilities such as
10
+ `motion-opacity-in-0 motion-duration-[400ms]`) are ungrouped, as a flag's
11
+ are, so all of them render. A component without a `component_class` groups
12
+ none of its own classes; globally configured grouped modifiers are unchanged
13
+ (#73).
14
+
15
+ ## [2.2.1] - 2026-10-27
16
+
17
+ ### Fixed
18
+
19
+ - The Tailwind sources generator accepts named groups and peers
20
+ (`group/item`, `group-has-[…]/item:block`, `peer-checked/field:block`) and a
21
+ plugin utility's named modifier (`motion-ease-in-out/opacity`) instead of
22
+ raising on them as paths. A bare word before the `/` (`app/components`) and a
23
+ second `/` (`lib/daisy_ui/base.rb`) are still rejected (#71).
24
+
25
+ ## [2.2.0] - 2026-10-26
26
+
3
27
  ### Documentation for the variants API
4
28
 
5
29
  - Docs site: "Variants, states and slots" (when to use `variant`, `flag`,
data/README.md CHANGED
@@ -269,6 +269,12 @@ dependency). daisyUI modifiers conflict when the component declares them as
269
269
  alternatives in one group: `btn-sm btn-lg` keeps `btn-lg`, while
270
270
  `dropdown-top dropdown-end` keeps both (placement and alignment are separate
271
271
  groups). Ungrouped modifiers (`btn-wide`, `btn-active`) never conflict.
272
+ A group holds only the component's own `<component_class>-*` classes: a
273
+ member's Tailwind utilities resolve by Tailwind's groups, and any other class
274
+ in it (a plugin utility such as `motion-duration-[400ms]`) never conflicts, so
275
+ the classes of one member never knock each other out. To make such classes
276
+ alternatives, set the component's `component_class` and name them
277
+ `<component_class>-*`, or register them with `class_groups` (below).
272
278
  Component base classes such as `table` and `collapse` are never dropped.
273
279
 
274
280
  Register custom utilities so the merger knows what they are. Unregistered,
@@ -382,7 +388,7 @@ Widget(:ghost, :sm) # btn font-medium btn-ghost btn-sm [--fontsize:…] [--btn-b
382
388
 
383
389
  | Declaration | |
384
390
  |---|---|
385
- | `variant :group, member: "classes", …` | Alternatives: the grouped `register_modifiers(group: { … })`. Members merge as one ClassMerge group. |
391
+ | `variant :group, member: "classes", …` | Alternatives: the grouped `register_modifiers(group: { … })`. Members' own `<component_class>-*` classes merge as one ClassMerge group. |
386
392
  | `flag :name, "classes"` | An on/off modifier: an ungrouped `register_modifiers` entry. `flag :name` alone is a `register_flags` flag, no class, for compounds to match. |
387
393
  | `base "classes"` | Classes every instance gets, appended to the inherited base. |
388
394
  | `default :group, :member` | The member used when the caller names none of the group. Never rendered beside a member the caller gives. |
@@ -8,8 +8,14 @@ module DaisyUI
8
8
  #
9
9
  # gives the group `daisy:group:btn-size` = ["btn-sm", "btn-lg"], so
10
10
  # `btn-sm btn-lg` merges to `btn-lg`. Ungrouped modifiers never conflict.
11
+ #
12
+ # A group holds only the component's own `<component_class>-*` classes.
11
13
  # Tokens Tailwind already classifies (`bg-primary text-primary-content`)
12
- # are left to the Tailwind groups, which resolve them per utility.
14
+ # are left to the Tailwind groups, which resolve them per utility. Any
15
+ # other class (a plugin utility such as `motion-duration-[400ms]`) is left
16
+ # ungrouped, as a flag is: a group would make the classes of one member
17
+ # knock each other out. A component without a component_class groups
18
+ # nothing of its own.
13
19
  #
14
20
  # Every gem component base class (`btn`, `table`) also gets a group of its
15
21
  # own and is never dropped, even where Tailwind has a utility of the same
@@ -33,14 +39,16 @@ module DaisyUI
33
39
  components.each do |component|
34
40
  component.modifier_groups.each do |group, members|
35
41
  tokens = members.flat_map { |member| component.modifiers[member].to_s.split }
36
- add(groups, "daisy:group:#{component.component_class || component.name}-#{group}", tokens, prefix)
42
+ add(groups, "daisy:group:#{component.component_class || component.name}-#{group}", own(tokens, component), prefix)
37
43
  end
38
44
  end
39
45
 
40
46
  # Configured modifiers join the component's own group of that name.
47
+ # A global one has no component to own its classes: all are grouped.
41
48
  configuration.modifiers.groups.each do |(component, group), classes|
42
49
  owner = component ? component.component_class || component.name : "global"
43
- add(groups, "daisy:group:#{owner}-#{group}", classes.flat_map(&:split), prefix)
50
+ tokens = classes.flat_map(&:split)
51
+ add(groups, "daisy:group:#{owner}-#{group}", component ? own(tokens, component) : tokens, prefix)
44
52
  end
45
53
 
46
54
  groups
@@ -68,6 +76,13 @@ module DaisyUI
68
76
 
69
77
  private
70
78
 
79
+ # The component's own modifier classes: `btn-sm` for `btn`.
80
+ def own(tokens, component)
81
+ return [] unless (base = component.component_class)
82
+
83
+ tokens.select { |token| token.start_with?("#{base}-") }
84
+ end
85
+
71
86
  # Subclasses share their parent's component_class and group names, so
72
87
  # their tokens land in the same group id and are unioned.
73
88
  def add(groups, id, tokens, prefix)
@@ -6,18 +6,24 @@ module DaisyUI
6
6
  # quoted string with brace expansion, and one unbalanced bracket in it
7
7
  # makes Tailwind drop every class after it, so a candidate starts and ends
8
8
  # like a utility or variant, has balanced () and [], and holds no quote,
9
- # brace, semicolon, backslash or backtick. A `/` only introduces a
10
- # fraction or an opacity (`w-1/2`, `bg-base-100/50`), never a path.
9
+ # brace, semicolon, backslash or backtick.
10
+ #
11
+ # A `/` before a digit or `[` is a fraction or an opacity (`w-1/2`,
12
+ # `bg-base-100/50`). A `/` before anything else is a path, except one
13
+ # trailing `/<name>` on a variant or utility: a named group or peer
14
+ # (`group/item`, `group-hover/item:underline`, `peer-checked/field:block`)
15
+ # or a plugin utility's named modifier (`motion-ease-in-out/opacity`).
11
16
  #
12
17
  # @api private
13
18
  module Candidate
14
19
  SHAPE = /\A[a-z@!\[*-][^\s"'`;{}\\]*[a-z0-9\])%!]\z/
15
20
  PATH = %r{/(?![0-9\[])}
21
+ NAMED = %r{\A(?<head>.+)/[A-Za-z0-9_-]+!?\z}
16
22
  CLOSING = { ")" => "(", "]" => "[" }.freeze
17
23
 
18
24
  class << self
19
25
  def valid?(token)
20
- SHAPE.match?(token) && token.match?(/[a-z]/) && !PATH.match?(token) && balanced?(token)
26
+ SHAPE.match?(token) && token.match?(/[a-z]/) && balanced?(token) && !paths?(token)
21
27
  end
22
28
 
23
29
  # The candidates among the whitespace-separated words of `classes`.
@@ -38,6 +44,35 @@ module DaisyUI
38
44
  end
39
45
  open.empty?
40
46
  end
47
+
48
+ def paths?(token)
49
+ parts(token).any? { |part| path?(part) }
50
+ end
51
+
52
+ def path?(part)
53
+ return false unless PATH.match?(part)
54
+
55
+ head = part[NAMED, :head]
56
+ head.nil? || PATH.match?(head) || !named?(head)
57
+ end
58
+
59
+ # What may carry a `/<name>`: a group or a peer, or a utility with a
60
+ # `-` in it. A bare word (`app`, `vendor`, `hover`) is a directory.
61
+ def named?(head)
62
+ %w[group peer].include?(head) || (head.include?("-") && SHAPE.match?(head))
63
+ end
64
+
65
+ # The token split on its top-level `:`, as Tailwind splits variants
66
+ # from the utility; a `:` inside [] or () belongs to its part.
67
+ def parts(token)
68
+ depth = 0
69
+ slices = token.each_char.slice_when do |char, _|
70
+ depth += 1 if "[(".include?(char)
71
+ depth -= 1 if "])".include?(char)
72
+ char == ":" && depth.zero?
73
+ end
74
+ slices.map { |chars| chars.join.delete_suffix(":") }
75
+ end
41
76
  end
42
77
  end
43
78
  end
@@ -3,5 +3,5 @@
3
3
  module DaisyUI
4
4
  # This timestamp is automatically updated when releasing a new version
5
5
  # Format: YYYY-MM-DD HH:MM:SS UTC
6
- UPDATED_AT = "2026-10-26 18:45:50 UTC"
6
+ UPDATED_AT = "2026-10-27 17:15:51 UTC"
7
7
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DaisyUI
4
- VERSION = "2.2.0"
4
+ VERSION = "2.2.2"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: daisyui
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 2.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mikael Henriksson