daisyui 1.1.1 → 1.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f5ead48d09f8c0ebcf05fedf37984540e379230cc2fad544c021867d76f0c111
4
- data.tar.gz: 1ae9c6477704ded3ce4d51276f8c842873f3890e19674536dc5fa46e6cb9183b
3
+ metadata.gz: d82c1b4f52e8a5b62fb723e83557c1def70805b24c855aced7381c8c2f80dc0e
4
+ data.tar.gz: 831d1acb486a33fb1b779643d273a58925a921a456d20be7374cf4a5ed6c3cf4
5
5
  SHA512:
6
- metadata.gz: 47b1925d05bbf36c2b02290e80db281689ae94080a4c93392ba9ed764a1d84beb7804cd2dd2536e06da3ed71aebfe255bed64bf6feef2a6aa78bbbddc239f342
7
- data.tar.gz: ffaf573ed0338c6c92ea6f57c44490081a218920e457ac7658f785d0c933958de950acfbbcb16ad87e179725da4c16fa60deec56660d6fd92424849a3c60f2f9
6
+ metadata.gz: 061d1ff9eb34a488db5ab1aff21491e9c4f8b39912c7749637e3941d9738edd5cbef993b5d52bd6e55620f4b6f4207f9ad7285df0f672507c3552f16be775d1a
7
+ data.tar.gz: 598db62e9eefc346e30b1d42d449bc49c54c6a80c5d917c21360fb1511ea0ed17380a2c9b2be8b4f1edd647d4281b5b134e18995be66ff1d884de17428a9d127
data/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ### Added
4
+
5
+ - Aura component (DaisyUI 5.6) with style variants (dual, rainbow, holo, gold, silver, glow) and sizes
6
+ - Megamenu component (DaisyUI 5.6) with wide, full, vertical modifiers, sizes, and active_indicator sub-component
7
+ - OTP component (DaisyUI 5.6) for one-time password inputs with configurable digit count, joined modifier, sizes, and color variants
8
+ - `Dropdown` `:popover` modifier — renders the menu via the native Popover API
9
+ and CSS anchor positioning, so it opens in the top layer and escapes
10
+ `overflow` clipping (e.g. inside a table's `overflow-x-auto`). Accepts a
11
+ `popover_id:` for a stable id. Wires `aria-controls`/`aria-expanded` on the
12
+ trigger and `role="menu"` on the menu popover (the latter overridable, and
13
+ omitted for non-menu `content` panels). Default and `:tap_to_close` dropdowns
14
+ are unchanged. See the README "Dropdown `:popover` positioning" note for the
15
+ optional older-browser polyfill.
16
+ - Opt-in `daisy-dropdown` Stimulus controller for `:popover` dropdowns
17
+ (`Dropdown(:popover, stimulus: true)`), delivered to importmap-rails apps via
18
+ a gated Rails engine that auto-pins it. Provides a feature-detected JS
19
+ positioning fallback (Safari < 26, Firefox < 147) and optional roving
20
+ keyboard navigation. The default `:popover` dropdown remains zero-JS, and the
21
+ gem stays a plain Phlex library when Rails is absent.
22
+
23
+ ### Changed
24
+
25
+ - Range component: added range-vertical modifier for vertical orientation (DaisyUI 5.6)
26
+ - Tooltip component: added alignment modifiers (tooltip-start, tooltip-center, tooltip-end) and tooltip-content sub-component (DaisyUI 5.6)
27
+
3
28
  ## [0.1.0] - 2024-08-02
4
29
 
5
30
  - Initial release
data/README.md CHANGED
@@ -152,6 +152,102 @@ plugins: [
152
152
  ],
153
153
  ```
154
154
 
155
+ ## Dropdown `:popover` positioning on older browsers
156
+
157
+ The `:popover` Dropdown modifier renders the menu in the browser top layer (so it
158
+ escapes `overflow` clipping) and positions it next to the trigger using **CSS
159
+ anchor positioning** (`anchor-name` / `position-anchor`). This works with **zero
160
+ JavaScript** on Chrome/Edge 125+, Safari 26+, and Firefox 147+.
161
+
162
+ ```ruby
163
+ Dropdown(:popover, :end) do |dropdown|
164
+ dropdown.button(:ghost, :sm) { "Actions" }
165
+ dropdown.menu(:sm, class: "w-52") do |menu|
166
+ menu.item { a(href: "#") { "Edit" } }
167
+ menu.item { a(href: "#") { "Delete" } }
168
+ end
169
+ end
170
+ ```
171
+
172
+ On **older engines (Safari < 26, Firefox < 147)** the popover still opens in the
173
+ top layer, but without CSS anchor positioning it falls back to the viewport
174
+ default (DaisyUI centers it via `@supports not (position-area)`), so it is not
175
+ positioned next to the trigger.
176
+
177
+ To position correctly on those browsers with no application code, pin the
178
+ [OddBird CSS anchor positioning polyfill](https://github.com/oddbird/css-anchor-positioning)
179
+ and load it lazily:
180
+
181
+ ```ruby
182
+ # config/importmap.rb
183
+ pin "@oddbird/css-anchor-positioning", to: "https://ga.jspm.io/npm:@oddbird/css-anchor-positioning@1/dist/css-anchor-positioning.fn.js", preload: false
184
+ ```
185
+
186
+ ```js
187
+ // app/javascript/application.js — load only when the browser lacks native support
188
+ if (!CSS.supports("anchor-name: --x")) {
189
+ import("@oddbird/css-anchor-positioning").then(({ default: polyfill }) => polyfill())
190
+ }
191
+ ```
192
+
193
+ Modern browsers fetch nothing extra; the polyfill loads only where it is needed.
194
+ For WAI-ARIA roving keyboard navigation inside `role="menu"` menus (which a CSS
195
+ polyfill cannot provide), see the optional Stimulus controller below.
196
+
197
+ ## Optional `daisy-dropdown` Stimulus controller
198
+
199
+ The `:popover` dropdown needs **no JavaScript** on modern browsers. For two
200
+ specific cases — a JS positioning fallback on browsers without CSS anchor
201
+ positioning, and roving keyboard navigation over `role="menu"` items — the gem
202
+ ships an **opt-in** Stimulus controller. It deliberately does **not** re-implement
203
+ open/toggle, light-dismiss, or Escape; the native Popover API already handles
204
+ those.
205
+
206
+ Under Rails with importmap-rails, the gem auto-pins the controller (no manual
207
+ pin). Register it once, lazily:
208
+
209
+ ```js
210
+ // app/javascript/controllers/index.js
211
+ import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading"
212
+ lazyLoadControllersFrom("daisy_ui/controllers", application)
213
+ ```
214
+
215
+ Then opt in per call site:
216
+
217
+ ```ruby
218
+ Dropdown(:popover, :end, stimulus: true) do |dropdown|
219
+ dropdown.button(:ghost, :sm) { "Actions" }
220
+ dropdown.menu(:sm, class: "w-52") do |menu|
221
+ menu.item { a(href: "#", role: "menuitem", tabindex: "-1") { "Edit" } }
222
+ end
223
+ end
224
+ ```
225
+
226
+ - `stimulus: true` wires the `daisy-dropdown` controller (namespaced to avoid
227
+ colliding with your own `dropdown` controller).
228
+ - `stimulus: "your-id"` overrides the identifier.
229
+ - The positioning fallback lazily imports `@floating-ui/dom` **only** when CSS
230
+ anchor positioning is unavailable (Safari < 26, Firefox < 147), so modern
231
+ browsers fetch nothing. The gem does **not** bundle it — if you enable the
232
+ controller **and** need to support those browsers, pin it yourself (lazy, so
233
+ modern browsers still skip it):
234
+
235
+ ```ruby
236
+ # config/importmap.rb
237
+ pin "@floating-ui/dom", to: "https://ga.jspm.io/npm:@floating-ui/dom@1.7.6/dist/floating-ui.dom.mjs", preload: false
238
+ ```
239
+
240
+ If the pin is missing the menu still opens (native popover) — it just won't be
241
+ repositioned on those legacy browsers, and the controller logs a console
242
+ warning. Evergreen-only apps can skip the pin entirely.
243
+ - Enable keyboard navigation with
244
+ `data: { daisy_dropdown_keyboard_value: true }` on the dropdown. Roving focus
245
+ targets `role="menuitem"` items, falling back to links/buttons in the menu.
246
+
247
+ JS-bundler (esbuild/vite/webpack) consumers: import the controller from the
248
+ gem's `app/javascript/daisy_ui/controllers/daisy_dropdown_controller.js` and
249
+ register it manually.
250
+
155
251
  # MCP Server (Claude Code Integration)
156
252
 
157
253
  This gem includes an MCP (Model Context Protocol) server that provides component information to AI assistants like Claude Code.
@@ -0,0 +1,170 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ // daisy-dropdown — OPT-IN enhancement for the :popover Dropdown variant.
4
+ //
5
+ // The native Popover API already handles open/toggle, light-dismiss (outside
6
+ // click), Escape, and focus return — so this controller deliberately does NOT
7
+ // re-implement any of that. Its only jobs are:
8
+ //
9
+ // 1. A positioning fallback for browsers WITHOUT CSS anchor positioning
10
+ // (Safari < 26, Firefox < 147). On modern browsers it does nothing and
11
+ // fetches no extra JavaScript. The fallback lazily imports @floating-ui/dom,
12
+ // which the HOST app must pin (see README) — if it is missing the menu still
13
+ // opens (native popover), just unpositioned, and a console warning is logged.
14
+ // 2. Optional roving keyboard navigation over the menu's focusable items
15
+ // (enable with data-daisy-dropdown-keyboard-value="true").
16
+ //
17
+ // State is driven entirely by the popover's native `toggle` event; there is no
18
+ // internal open flag, no document-level listeners, and no display toggling.
19
+ const OFFSET = 4
20
+
21
+ // Focusable, interactive menu items. Prefers explicit role="menuitem", but falls
22
+ // back to the links/buttons DaisyUI menus actually render (<li><a>…</a></li>), so
23
+ // keyboard nav works on stock markup without forcing roles onto caller content.
24
+ const ITEM_SELECTOR = '[role="menuitem"]:not([aria-disabled="true"]), a[href]:not([aria-disabled="true"]), button:not([disabled])'
25
+
26
+ export default class extends Controller {
27
+ static targets = ["trigger", "menu"]
28
+ static values = { keyboard: { type: Boolean, default: false } }
29
+
30
+ connect() {
31
+ this.menuEl = this.hasMenuTarget ? this.menuTarget : this.element.querySelector("[popover]")
32
+ this.triggerEl = this.hasTriggerTarget ? this.triggerTarget : this.element.querySelector("[popovertarget]")
33
+ if (!this.menuEl) return
34
+
35
+ this.needsJsPositioning = !this.#supportsAnchorPositioning()
36
+ this.onToggle = (event) => this.#handleToggle(event)
37
+ this.menuEl.addEventListener("toggle", this.onToggle)
38
+ }
39
+
40
+ disconnect() {
41
+ this.menuEl?.removeEventListener("toggle", this.onToggle)
42
+ this.#teardownOpen()
43
+ }
44
+
45
+ #handleToggle(event) {
46
+ if (event.newState === "open") this.#onOpen()
47
+ else this.#onClose()
48
+ }
49
+
50
+ async #onOpen() {
51
+ // The native Popover API does not mirror open state onto the invoker, so
52
+ // sync aria-expanded ourselves for assistive tech.
53
+ this.triggerEl?.setAttribute("aria-expanded", "true")
54
+ if (this.needsJsPositioning) await this.#position()
55
+ if (this.keyboardValue) this.#bindKeyboard()
56
+ }
57
+
58
+ #onClose() {
59
+ this.triggerEl?.setAttribute("aria-expanded", "false")
60
+ this.#teardownOpen()
61
+ // Do NOT restore focus — the native popover already returns focus to the trigger.
62
+ }
63
+
64
+ #isOpen() {
65
+ return this.menuEl?.matches(":popover-open") ?? false
66
+ }
67
+
68
+ #teardownOpen() {
69
+ this.stopAutoUpdate?.()
70
+ this.stopAutoUpdate = null
71
+ if (this.keyHandler) {
72
+ this.menuEl?.removeEventListener("keydown", this.keyHandler)
73
+ this.keyHandler = null
74
+ }
75
+ }
76
+
77
+ // --- positioning fallback (only when CSS anchor positioning is unavailable) ---
78
+
79
+ async #position() {
80
+ if (!this.triggerEl) return
81
+
82
+ // Lazy + feature-gated, so modern browsers never fetch the positioning lib.
83
+ // The host app is responsible for pinning @floating-ui/dom; if it is absent
84
+ // we degrade gracefully (native popover still opens, just unpositioned).
85
+ let floatingUi
86
+ try {
87
+ floatingUi = await import("@floating-ui/dom")
88
+ } catch (error) {
89
+ console.warn(
90
+ "[daisy-dropdown] @floating-ui/dom is not available; the popover will open unpositioned. " +
91
+ "Pin it in your import map to enable the legacy-browser positioning fallback.",
92
+ error,
93
+ )
94
+ return
95
+ }
96
+
97
+ // A fast open→close during the dynamic import may have already closed us;
98
+ // bail rather than position (and leak an autoUpdate on) a closed menu.
99
+ if (!this.#isOpen()) return
100
+
101
+ const { computePosition, autoUpdate, flip, shift, offset } = floatingUi
102
+
103
+ this.menuEl.style.position = "fixed"
104
+ this.menuEl.style.margin = "0"
105
+
106
+ this.stopAutoUpdate = autoUpdate(this.triggerEl, this.menuEl, () => {
107
+ computePosition(this.triggerEl, this.menuEl, {
108
+ placement: this.#placement(),
109
+ middleware: [offset(OFFSET), flip(), shift({ padding: 8 })],
110
+ }).then(({ x, y }) => {
111
+ Object.assign(this.menuEl.style, { left: `${x}px`, top: `${y}px` })
112
+ })
113
+ })
114
+ }
115
+
116
+ // Derive Floating UI placement from DaisyUI's dropdown-* classes on the menu.
117
+ #placement() {
118
+ const cl = this.menuEl.classList
119
+ const side = cl.contains("dropdown-top")
120
+ ? "top"
121
+ : cl.contains("dropdown-left")
122
+ ? "left"
123
+ : cl.contains("dropdown-right")
124
+ ? "right"
125
+ : "bottom"
126
+ const align = cl.contains("dropdown-end") ? "-end" : cl.contains("dropdown-center") ? "" : "-start"
127
+ return (side === "left" || side === "right") ? side : `${side}${align}`
128
+ }
129
+
130
+ // --- optional roving keyboard navigation ---
131
+
132
+ #bindKeyboard() {
133
+ this.keyHandler = (event) => this.#onKeydown(event)
134
+ this.menuEl.addEventListener("keydown", this.keyHandler)
135
+ this.#items()[0]?.focus()
136
+ }
137
+
138
+ #onKeydown(event) {
139
+ const items = this.#items()
140
+ if (items.length === 0) return
141
+ const index = items.indexOf(document.activeElement)
142
+
143
+ switch (event.key) {
144
+ case "ArrowDown":
145
+ event.preventDefault()
146
+ items[(index + 1 + items.length) % items.length].focus()
147
+ break
148
+ case "ArrowUp":
149
+ event.preventDefault()
150
+ items[(index - 1 + items.length) % items.length].focus()
151
+ break
152
+ case "Home":
153
+ event.preventDefault()
154
+ items[0].focus()
155
+ break
156
+ case "End":
157
+ event.preventDefault()
158
+ items[items.length - 1].focus()
159
+ break
160
+ }
161
+ }
162
+
163
+ #items() {
164
+ return Array.from(this.menuEl.querySelectorAll(ITEM_SELECTOR))
165
+ }
166
+
167
+ #supportsAnchorPositioning() {
168
+ return typeof CSS !== "undefined" && typeof CSS.supports === "function" && CSS.supports("anchor-name: --x")
169
+ }
170
+ }
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Auto-pins the gem's bundled Stimulus controllers for importmap-rails consumers.
4
+ # Exposes `daisy_ui/controllers/daisy_dropdown_controller`. Register it in the
5
+ # host app (lazily recommended):
6
+ #
7
+ # // app/javascript/controllers/index.js
8
+ # import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading"
9
+ # lazyLoadControllersFrom("daisy_ui/controllers", application)
10
+ pin_all_from DaisyUI::Engine.root.join("app/javascript/daisy_ui/controllers"),
11
+ under: "daisy_ui/controllers",
12
+ to: "daisy_ui/controllers"
@@ -14,8 +14,8 @@ module DaisyUI
14
14
  def view_template(&block)
15
15
  public_send(as, class: classes, **attributes) do
16
16
  input(type: :radio, name:, checked:)
17
- div(class: build_title_classes, &title_block) if title_block
18
- div(class: "collapse-content", &block) if block
17
+ div(class: component_classes("collapse-title", options: title_options || {}), &title_block) if title_block
18
+ div(class: component_classes("collapse-content", options: {}), &block) if block
19
19
  end
20
20
  end
21
21
 
@@ -28,28 +28,34 @@ module DaisyUI
28
28
 
29
29
  attr_reader :name, :checked, :title_block, :title_options
30
30
 
31
- def build_title_classes
32
- classes = ["collapse-title"]
33
- classes << title_options.delete(:class) if title_options&.dig(:class)
34
- classes.compact.join(" ")
35
- end
36
-
37
31
  register_modifiers(
38
32
  # "sm:collapse-arrow"
33
+ # "@sm:collapse-arrow"
39
34
  # "md:collapse-arrow"
35
+ # "@md:collapse-arrow"
40
36
  # "lg:collapse-arrow"
37
+ # "@lg:collapse-arrow"
41
38
  arrow: "collapse-arrow",
42
39
  # "sm:collapse-plus"
40
+ # "@sm:collapse-plus"
43
41
  # "md:collapse-plus"
42
+ # "@md:collapse-plus"
44
43
  # "lg:collapse-plus"
44
+ # "@lg:collapse-plus"
45
45
  plus: "collapse-plus",
46
46
  # "sm:collapse-open"
47
+ # "@sm:collapse-open"
47
48
  # "md:collapse-open"
49
+ # "@md:collapse-open"
48
50
  # "lg:collapse-open"
51
+ # "@lg:collapse-open"
49
52
  open: "collapse-open",
50
53
  # "sm:collapse-close"
54
+ # "@sm:collapse-close"
51
55
  # "md:collapse-close"
56
+ # "@md:collapse-close"
52
57
  # "lg:collapse-close"
58
+ # "@lg:collapse-close"
53
59
  close: "collapse-close"
54
60
  )
55
61
  end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DaisyUI
4
+ class Aura < Base
5
+ self.component_class = :aura
6
+
7
+ def view_template(&)
8
+ public_send(as, class: classes, **attributes, &)
9
+ end
10
+
11
+ register_modifiers(
12
+ # Styles
13
+ # "sm:aura-dual"
14
+ # "@sm:aura-dual"
15
+ # "md:aura-dual"
16
+ # "@md:aura-dual"
17
+ # "lg:aura-dual"
18
+ # "@lg:aura-dual"
19
+ dual: "aura-dual",
20
+ # "sm:aura-rainbow"
21
+ # "@sm:aura-rainbow"
22
+ # "md:aura-rainbow"
23
+ # "@md:aura-rainbow"
24
+ # "lg:aura-rainbow"
25
+ # "@lg:aura-rainbow"
26
+ rainbow: "aura-rainbow",
27
+ # "sm:aura-holo"
28
+ # "@sm:aura-holo"
29
+ # "md:aura-holo"
30
+ # "@md:aura-holo"
31
+ # "lg:aura-holo"
32
+ # "@lg:aura-holo"
33
+ holo: "aura-holo",
34
+ # "sm:aura-gold"
35
+ # "@sm:aura-gold"
36
+ # "md:aura-gold"
37
+ # "@md:aura-gold"
38
+ # "lg:aura-gold"
39
+ # "@lg:aura-gold"
40
+ gold: "aura-gold",
41
+ # "sm:aura-silver"
42
+ # "@sm:aura-silver"
43
+ # "md:aura-silver"
44
+ # "@md:aura-silver"
45
+ # "lg:aura-silver"
46
+ # "@lg:aura-silver"
47
+ silver: "aura-silver",
48
+ # "sm:aura-glow"
49
+ # "@sm:aura-glow"
50
+ # "md:aura-glow"
51
+ # "@md:aura-glow"
52
+ # "lg:aura-glow"
53
+ # "@lg:aura-glow"
54
+ glow: "aura-glow",
55
+ # Sizes
56
+ # "sm:aura-xs"
57
+ # "@sm:aura-xs"
58
+ # "md:aura-xs"
59
+ # "@md:aura-xs"
60
+ # "lg:aura-xs"
61
+ # "@lg:aura-xs"
62
+ xs: "aura-xs",
63
+ # "sm:aura-sm"
64
+ # "@sm:aura-sm"
65
+ # "md:aura-sm"
66
+ # "@md:aura-sm"
67
+ # "lg:aura-sm"
68
+ # "@lg:aura-sm"
69
+ sm: "aura-sm",
70
+ # "sm:aura-md"
71
+ # "@sm:aura-md"
72
+ # "md:aura-md"
73
+ # "@md:aura-md"
74
+ # "lg:aura-md"
75
+ # "@lg:aura-md"
76
+ md: "aura-md",
77
+ # "sm:aura-lg"
78
+ # "@sm:aura-lg"
79
+ # "md:aura-lg"
80
+ # "@md:aura-lg"
81
+ # "lg:aura-lg"
82
+ # "@lg:aura-lg"
83
+ lg: "aura-lg",
84
+ # "sm:aura-xl"
85
+ # "@sm:aura-xl"
86
+ # "md:aura-xl"
87
+ # "@md:aura-xl"
88
+ # "lg:aura-xl"
89
+ # "@lg:aura-xl"
90
+ xl: "aura-xl"
91
+ )
92
+ end
93
+ end
data/lib/daisy_ui/base.rb CHANGED
@@ -224,7 +224,7 @@ module DaisyUI
224
224
  base_class_value = self.class.component_class
225
225
  next unless base_class_value
226
226
 
227
- "#{breakpoint}:#{apply_prefix(base_class_value)}"
227
+ "#{breakpoint}:#{apply_prefix(base_class_value.to_s)}"
228
228
  else
229
229
  # Get the modifier classes (may be multiple like "bg-primary text-primary-content")
230
230
  modifier_classes = modifier_map[mod]
@@ -11,7 +11,7 @@ module DaisyUI
11
11
  end
12
12
 
13
13
  def crumb(href: nil, **options, &block)
14
- li(class: component_classes(options: options), **options) do
14
+ li(class: component_classes(options:), **options) do
15
15
  if href
16
16
  a(href: href, &block)
17
17
  else
@@ -31,7 +31,12 @@ module DaisyUI
31
31
 
32
32
  register_modifiers(
33
33
  # Styles
34
- # "sm:btn-ghost" "md:btn-ghost" "lg:btn-ghost"
34
+ # "sm:btn-ghost"
35
+ # "@sm:btn-ghost"
36
+ # "md:btn-ghost"
37
+ # "@md:btn-ghost"
38
+ # "lg:btn-ghost"
39
+ # "@lg:btn-ghost"
35
40
  ghost: "btn-ghost",
36
41
  # "sm:btn-link"
37
42
  # "@sm:btn-link"
@@ -28,12 +28,12 @@ module DaisyUI
28
28
  # "lg:carousel-center"
29
29
  # "@lg:carousel-center"
30
30
  center: "carousel-center",
31
- # "sm:carousel-end"
32
- # "@sm:carousel-end"
33
- # "md:carousel-end"
34
- # "@md:carousel-end"
35
- # "lg:carousel-end"
36
- # "@lg:carousel-end"
31
+ # "sm:carousel-end"
32
+ # "@sm:carousel-end"
33
+ # "md:carousel-end"
34
+ # "@md:carousel-end"
35
+ # "lg:carousel-end"
36
+ # "@lg:carousel-end"
37
37
  end: "carousel-end",
38
38
  # "sm:carousel-vertical"
39
39
  # "@sm:carousel-vertical"
data/lib/daisy_ui/chat.rb CHANGED
@@ -107,12 +107,8 @@ module DaisyUI
107
107
  private
108
108
 
109
109
  def build_bubble_classes(modifiers, options)
110
- classes = ["chat-bubble"]
111
- modifiers.each do |mod|
112
- classes << BUBBLE_MODIFIERS[mod] if BUBBLE_MODIFIERS.key?(mod)
113
- end
114
- classes << options.delete(:class) if options[:class]
115
- classes.compact.join(" ")
110
+ modifier_classes = modifiers.filter_map { |mod| apply_prefix(BUBBLE_MODIFIERS[mod]) }
111
+ merge_classes(apply_prefix("chat-bubble"), *modifier_classes, options.delete(:class))
116
112
  end
117
113
  end
118
114
  end
@@ -7,7 +7,7 @@ module DaisyUI
7
7
 
8
8
  def initialize(*, **)
9
9
  super
10
- @items ||= []
10
+ @items = []
11
11
  end
12
12
 
13
13
  def view_template(&block)