daisyui 1.0.2 → 1.0.3

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: 75db7da2ecbc50158da82bbf662b754ed98691102f006f24298f2d754f33e27b
4
- data.tar.gz: 036e8f6362a4fedf58a2d924ea40ab5720006224e2bc71f3c9b8aef42bd9b1e3
3
+ metadata.gz: 0dfd69755019e48481d090083a5165c37b04d50af7d76b145a2f76dae4ebb594
4
+ data.tar.gz: c4b804a2a61d7018f6db355629b9d90525dfe89508b63a236829d7dcd72e25a6
5
5
  SHA512:
6
- metadata.gz: 708df86e95e6c50e3a2270d299a0b13147ae78d56b660b7fa6ea0867258ed964006aa23c104123d9ba4db5dfab1c42b49735190e3937892be792d37fc3ba0aae
7
- data.tar.gz: 8009d960b83e5bd5033469a10d59bb1d1d254d4e244356250df01ccf0ef6f35f34dec000a398c4733c6d8bf8e78cefbe26a76c9b845289923aea6e383ba91898
6
+ metadata.gz: 976568cac60b3cb8ce9ce4d1270630660dd60507447c6e4304336f7c58296204a84acbc4ccc41dc628f17b77180cf5b75a6889d28ce7a3f424aba064a0914183
7
+ data.tar.gz: b7c07d86fe55bc2722e6730dcd021197d8f98b13e54d0560736bc7e97d57f38bd1bd6da028ee7fc99f5ddb1c5077093094bf2c67205e04a7697e7bcad3f02f0c
@@ -8,8 +8,6 @@ module DaisyUI
8
8
  public_send(as, role: :alert, class: classes, **attributes, &)
9
9
  end
10
10
 
11
- private
12
-
13
11
  register_modifiers(
14
12
  # "sm:alert-info"
15
13
  # "@sm:alert-info"
@@ -8,8 +8,6 @@ module DaisyUI
8
8
  public_send(as, class: classes, **attributes, &)
9
9
  end
10
10
 
11
- private
12
-
13
11
  register_modifiers(
14
12
  # "sm:online"
15
13
  # "@sm:online"
@@ -8,8 +8,8 @@ module DaisyUI
8
8
  public_send(as, class: classes, **attributes, &)
9
9
  end
10
10
 
11
- def avatar(*, **, &)
12
- render DaisyUI::Avatar.new(*, **, &)
11
+ def avatar(...)
12
+ render DaisyUI::Avatar.new(...)
13
13
  end
14
14
  end
15
15
  end
@@ -12,8 +12,6 @@ module DaisyUI
12
12
  public_send(as, class: classes, **attributes, &)
13
13
  end
14
14
 
15
- private
16
-
17
15
  register_modifiers(
18
16
  # "sm:badge-neutral"
19
17
  # "@sm:badge-neutral"
data/lib/daisy_ui/base.rb CHANGED
@@ -1,7 +1,41 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DaisyUI
4
+ # Base class for all DaisyUI components.
5
+ #
6
+ # ## Architecture Overview
7
+ #
8
+ # Components accept three types of arguments:
9
+ # 1. **Modifiers** - Positional symbol arguments that map to DaisyUI CSS classes
10
+ # Example: Dropdown.new(:top, :hover) → "dropdown-top dropdown-hover"
11
+ #
12
+ # 2. **Options** - Keyword arguments for the component (as:, id:)
13
+ # Example: Dropdown.new(as: :div, id: "my-dropdown")
14
+ #
15
+ # 3. **Attributes** - Additional keyword arguments for HTML attributes (data:, aria:, class:)
16
+ # Example: Dropdown.new(data: {controller: "dropdown"}, class: "my-custom-class")
17
+ #
18
+ # ## Key Methods
19
+ #
20
+ # - `classes` - Builds the final CSS class string by combining base class,
21
+ # modifiers, responsive classes, and user-provided classes. DESTRUCTIVELY
22
+ # removes :class from options.
23
+ #
24
+ # - `attributes` - Returns the hash of HTML attributes to splat into the element.
25
+ # By default includes all remaining options (after :class was removed) plus :id.
26
+ # Override in subclasses if different behavior is needed.
27
+ #
28
+ # ## Typical Usage Pattern
29
+ #
30
+ # In a component's view_template:
31
+ # def view_template(&)
32
+ # div(class: classes, **attributes, &)
33
+ # end
34
+ #
35
+ # This renders: <div class="[generated classes]" id="..." data-...="..." ...>
36
+ #
4
37
  class Base < Phlex::HTML
38
+ BOOLS = [true, false].freeze
5
39
  # Shared color modifiers used across multiple components
6
40
  # Maps color names to their DaisyUI background/text class combinations
7
41
  COLOR_MODIFIERS = {
@@ -105,9 +139,9 @@ module DaisyUI
105
139
  super
106
140
  subclass.modifiers = (modifiers || {}).dup
107
141
  # Inherit component_class if it was explicitly set
108
- if instance_variable_defined?(:@component_class)
109
- subclass.component_class = @component_class
110
- end
142
+ return unless instance_variable_defined?(:@component_class)
143
+
144
+ subclass.component_class = @component_class
111
145
  end
112
146
 
113
147
  def register_modifiers(mods)
@@ -122,7 +156,10 @@ module DaisyUI
122
156
  @modifiers = modifiers + boolean_modifiers
123
157
  @as = as
124
158
  @id = id
159
+ # Store all keyword arguments (class, data, aria, etc.)
160
+ # This will be processed by `classes` and `attributes` methods
125
161
  @options = options
162
+ super()
126
163
  end
127
164
 
128
165
  private
@@ -130,6 +167,15 @@ module DaisyUI
130
167
  attr_reader :modifiers, :options, :as, :id
131
168
 
132
169
  # Main extension points - override these in your project!
170
+
171
+ # Builds the final CSS class string from:
172
+ # 1. Component base class (e.g., "dropdown")
173
+ # 2. Modifier classes (e.g., "dropdown-top")
174
+ # 3. Responsive classes (e.g., "sm:dropdown-hover")
175
+ # 4. User-provided classes via `class:` option
176
+ #
177
+ # Note: This method DESTRUCTIVELY removes :class from options
178
+ # so it won't appear again in attributes
133
179
  def classes
134
180
  merge_classes(
135
181
  base_class,
@@ -139,8 +185,15 @@ module DaisyUI
139
185
  )
140
186
  end
141
187
 
188
+ # Returns the hash of HTML attributes to splat into the element.
189
+ # By default, includes all options (except :class which was removed by `classes`)
190
+ # and adds :id if provided.
191
+ #
192
+ # Override this method in subclasses if you need different behavior.
193
+ # For example, Drawer overrides this to exclude :id because it uses
194
+ # id internally for toggle/overlay elements.
142
195
  def attributes
143
- merge_attributes(**options)
196
+ options.dup.merge(id: id).compact
144
197
  end
145
198
 
146
199
  # Simple defaults - easy to override
@@ -149,16 +202,10 @@ module DaisyUI
149
202
  result.empty? ? nil : result
150
203
  end
151
204
 
152
- def merge_attributes(**attrs)
153
- attrs
154
- end
155
-
156
205
  # Core functionality
157
206
  def base_class
158
207
  # If responsive option includes `true`, base class should only appear with responsive prefix
159
- if options[:responsive]&.values&.any? { |mods| Array(mods).include?(true) }
160
- return nil
161
- end
208
+ return nil if options[:responsive]&.values&.any? { |mods| Array(mods).include?(true) }
162
209
 
163
210
  apply_prefix(self.class.component_class&.to_s)
164
211
  end
@@ -206,9 +253,7 @@ module DaisyUI
206
253
  boolean_mods = []
207
254
 
208
255
  modifier_keys.each do |key|
209
- if options.key?(key) && (options[key] == true || options[key] == false)
210
- boolean_mods << key if options.delete(key) == true
211
- end
256
+ boolean_mods << key if options.key?(key) && BOOLS.include?(options[key]) && (options.delete(key) == true)
212
257
  end
213
258
 
214
259
  boolean_mods
@@ -13,8 +13,8 @@ module DaisyUI
13
13
  def crumb(**options, &)
14
14
  li(class: component_classes(options: options), **options, &)
15
15
  end
16
- alias_method :breadcrumb, :crumb
17
- alias_method :item, :crumb
16
+ alias breadcrumb crumb
17
+ alias item crumb
18
18
 
19
19
  register_modifiers({})
20
20
  end
@@ -28,8 +28,8 @@ module DaisyUI
28
28
 
29
29
  attr_reader :type
30
30
 
31
- def render_cally(&block)
32
- calendar_date(class: classes, **attributes, &block)
31
+ def render_cally(&)
32
+ calendar_date(class: classes, **attributes, &)
33
33
  end
34
34
 
35
35
  def render_pikaday
@@ -18,12 +18,10 @@ module DaisyUI
18
18
  details_attrs[:open] = true if modifiers.include?(:open) || options.delete(:open) == true
19
19
 
20
20
  details(**details_attrs) do
21
- if @title
22
- summary do
23
- render @title
24
- end
25
- else
26
- raise ArgumentError, "A collapsible submenu requires a title"
21
+ raise ArgumentError, "A collapsible submenu requires a title" unless @title
22
+
23
+ summary do
24
+ render @title
27
25
  end
28
26
 
29
27
  if @items.any?
@@ -37,18 +35,14 @@ module DaisyUI
37
35
  end
38
36
 
39
37
  def title(&block)
40
- if @title
41
- raise ArgumentError, "A collapsible submenu can only have one title"
42
- else
43
- @title = block
44
- end
45
- end
38
+ raise ArgumentError, "A collapsible submenu can only have one title" if @title
46
39
 
47
- def item(*, **, &)
48
- @items << MenuItem.new(*, **, &)
40
+ @title = block
49
41
  end
50
42
 
51
- private
43
+ def item(...)
44
+ @items << MenuItem.new(...)
45
+ end
52
46
 
53
47
  register_modifiers(COLOR_MODIFIERS)
54
48
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DaisyUI
2
4
  module Configurable
3
5
  def configure
@@ -37,6 +37,14 @@ module DaisyUI
37
37
 
38
38
  private
39
39
 
40
+ # Override Base#attributes to exclude :id from the main drawer element.
41
+ # The Drawer component requires an :id parameter, but it's used internally
42
+ # to wire up the toggle checkbox, overlay, and button elements - NOT for
43
+ # the main drawer container.
44
+ def attributes
45
+ options
46
+ end
47
+
40
48
  register_modifiers(
41
49
  # "sm:drawer-end"
42
50
  # "@sm:drawer-end"
@@ -4,8 +4,12 @@ module DaisyUI
4
4
  class Dropdown < Base
5
5
  self.component_class = :dropdown
6
6
 
7
+ def initialize(*modifiers, as: :div, id: nil, **options)
8
+ super
9
+ end
10
+
7
11
  def view_template(&)
8
- if modifiers.include?(:tap_to_close)
12
+ if tap_to_close?
9
13
  details(class: classes, **attributes, &)
10
14
  else
11
15
  public_send(as, class: classes, **attributes, &)
@@ -13,7 +17,7 @@ module DaisyUI
13
17
  end
14
18
 
15
19
  def button(*, **, &)
16
- if modifiers.include?(:tap_to_close)
20
+ if tap_to_close?
17
21
  render Button.new(*, as: :summary, **, &)
18
22
  else
19
23
  render Button.new(*, as: :div, role: :button, tabindex: 0, **, &)
@@ -23,7 +27,7 @@ module DaisyUI
23
27
  def content(*, as: :div, **options, &)
24
28
  content_classes = component_classes("dropdown-content", options:)
25
29
 
26
- if modifiers.include?(:tap_to_close)
30
+ if tap_to_close?
27
31
  render_as(*, as:, class: content_classes, **options, &)
28
32
  else
29
33
  render_as(*, as:, tabindex: 0, class: content_classes, **options, &)
@@ -33,14 +37,16 @@ module DaisyUI
33
37
  def menu(*, **options, &)
34
38
  menu_classes = component_classes("dropdown-content", options:)
35
39
 
36
- if modifiers.include?(:tap_to_close)
40
+ if tap_to_close?
37
41
  render Menu.new(*, class: menu_classes, **options, &)
38
42
  else
39
43
  render Menu.new(*, tabindex: 0, class: menu_classes, **options, &)
40
44
  end
41
45
  end
42
46
 
43
- private
47
+ def tap_to_close?
48
+ modifiers.include?(:tap_to_close)
49
+ end
44
50
 
45
51
  register_modifiers(
46
52
  # "sm:dropdown-end"
@@ -54,7 +54,7 @@ module DaisyUI
54
54
  # label.text("Username")
55
55
  # label.text { "Email Address" }
56
56
  # label.text("https://", class: "custom-class")
57
- def text(content = nil, **options, &block)
57
+ def text(content = nil, **options)
58
58
  span(class: component_classes("label", options:), **options) do
59
59
  content || yield
60
60
  end
@@ -12,8 +12,6 @@ module DaisyUI
12
12
  public_send(as, class: classes, **attributes, &)
13
13
  end
14
14
 
15
- private
16
-
17
15
  register_modifiers(
18
16
  # "sm:loading-spinner"
19
17
  # "@sm:loading-spinner"
data/lib/daisy_ui/mask.rb CHANGED
@@ -8,8 +8,6 @@ module DaisyUI
8
8
  public_send(as, class: classes, **attributes, &)
9
9
  end
10
10
 
11
- private
12
-
13
11
  register_modifiers(
14
12
  # "sm:mask-squircle"
15
13
  # "@sm:mask-squircle"
data/lib/daisy_ui/menu.rb CHANGED
@@ -12,8 +12,8 @@ module DaisyUI
12
12
  public_send(as, class: component_classes("menu-title", options:), **options, &)
13
13
  end
14
14
 
15
- def item(*, **, &)
16
- render MenuItem.new(*, **, &)
15
+ def item(...)
16
+ render MenuItem.new(...)
17
17
  end
18
18
 
19
19
  def submenu(*modifiers, **, &)
@@ -28,8 +28,6 @@ module DaisyUI
28
28
  end
29
29
  end
30
30
 
31
- private
32
-
33
31
  register_modifiers(
34
32
  # "sm:menu-xs"
35
33
  # "@sm:menu-xs"
@@ -9,20 +9,18 @@ module DaisyUI
9
9
  li(class: classes, **attributes, &)
10
10
  end
11
11
 
12
- def title(*, **options, &block)
13
- h2(class: component_classes("menu-title", options:), **options, &block)
12
+ def title(*, **options, &)
13
+ h2(class: component_classes("menu-title", options:), **options, &)
14
14
  end
15
15
 
16
- def submenu(*modifiers, **options, &)
16
+ def submenu(*modifiers, **, &)
17
17
  if modifiers.include?(:collapsible)
18
- render CollapsibleSubMenu.new(*modifiers, **options, &)
18
+ render CollapsibleSubMenu.new(*modifiers, **, &)
19
19
  else
20
- render SubMenu.new(*modifiers, **options, &)
20
+ render SubMenu.new(*modifiers, **, &)
21
21
  end
22
22
  end
23
23
 
24
- private
25
-
26
24
  register_modifiers(
27
25
  # "sm:disabled"
28
26
  # "@sm:disabled"
@@ -41,8 +41,6 @@ module DaisyUI
41
41
  end
42
42
  end
43
43
 
44
- private
45
-
46
44
  register_modifiers(
47
45
  # "sm:modal-open"
48
46
  # "@sm:modal-open"
@@ -8,8 +8,6 @@ module DaisyUI
8
8
  public_send(as, class: classes, **attributes, &)
9
9
  end
10
10
 
11
- private
12
-
13
11
  register_modifiers({})
14
12
  end
15
13
  end
@@ -17,11 +17,11 @@ module DaisyUI
17
17
  end
18
18
  end
19
19
 
20
- if @items.any?
21
- ul do
22
- @items.each do |item|
23
- render item
24
- end
20
+ return unless @items.any?
21
+
22
+ ul do
23
+ @items.each do |item|
24
+ render item
25
25
  end
26
26
  end
27
27
  end
@@ -30,8 +30,8 @@ module DaisyUI
30
30
  @title = block
31
31
  end
32
32
 
33
- def item(*, **, &)
34
- @items << MenuItem.new(*, **, &)
33
+ def item(...)
34
+ @items << MenuItem.new(...)
35
35
  end
36
36
  end
37
37
  end
data/lib/daisy_ui/tab.rb CHANGED
@@ -3,8 +3,8 @@
3
3
  module DaisyUI
4
4
  # @private
5
5
  class Tab < Base
6
- def initialize(*modifiers, label: nil, id: nil, **options)
7
- super(*modifiers, **options)
6
+ def initialize(*modifiers, label: nil, id: nil, **)
7
+ super(*modifiers, **)
8
8
  @label = label
9
9
  @id = id
10
10
  end
@@ -31,7 +31,7 @@ module DaisyUI
31
31
  "You must pass an id to Tabs#new if you want to add content"
32
32
  end
33
33
 
34
- @content = -> do
34
+ @content = lambda do
35
35
  content_classes = component_classes("tab-content", options:)
36
36
  div role: :tabpanel, class: content_classes, **options, &block
37
37
  end
@@ -17,9 +17,9 @@ module DaisyUI
17
17
  tab_attrs = {
18
18
  type: :radio,
19
19
  name: id,
20
- class: classes, # This deletes :class from options
20
+ class: classes, # This deletes :class from options
21
21
  role: :tab,
22
- aria: {label: @label}
22
+ aria: { label: @label }
23
23
  }
24
24
 
25
25
  # Now get remaining attributes (class has been deleted by classes method)
@@ -52,6 +52,13 @@ module DaisyUI
52
52
 
53
53
  private
54
54
 
55
+ # Override Base#attributes to exclude :id from the tab input.
56
+ # The TabWithContent component uses :id for the `name` attribute
57
+ # to group radio inputs together - NOT for the id attribute.
58
+ def attributes
59
+ options
60
+ end
61
+
55
62
  register_modifiers(
56
63
  # "sm:tab-active"
57
64
  # "@sm:tab-active"
@@ -18,8 +18,6 @@ module DaisyUI
18
18
  div role: :tab, class: classes, **attrs, &
19
19
  end
20
20
 
21
- private
22
-
23
21
  register_modifiers(
24
22
  # "sm:tab-active"
25
23
  # "@sm:tab-active"
@@ -8,24 +8,22 @@ module DaisyUI
8
8
  table(class: classes, **attributes, &)
9
9
  end
10
10
 
11
- def header(*, **, &)
12
- thead(*, **, &)
11
+ def header(...)
12
+ thead(...)
13
13
  end
14
14
 
15
- def row(*, **, &)
16
- render TableRow.new(*, **, &)
15
+ def row(...)
16
+ render TableRow.new(...)
17
17
  end
18
18
 
19
- def body(*, **, &)
20
- tbody(*, **, &)
19
+ def body(...)
20
+ tbody(...)
21
21
  end
22
22
 
23
- def footer(*, **, &)
24
- tfoot(*, **, &)
23
+ def footer(...)
24
+ tfoot(...)
25
25
  end
26
26
 
27
- private
28
-
29
27
  register_modifiers(
30
28
  # "sm:table-zebra"
31
29
  # "@sm:table-zebra"
@@ -8,16 +8,14 @@ module DaisyUI
8
8
  tr(class: classes, **attributes, &)
9
9
  end
10
10
 
11
- def head(*, **, &)
12
- th(*, **, &)
11
+ def head(...)
12
+ th(...)
13
13
  end
14
14
 
15
- def column(*, **, &)
16
- td(*, **, &)
15
+ def column(...)
16
+ td(...)
17
17
  end
18
- alias_method :cell, :column
19
-
20
- private
18
+ alias cell column
21
19
 
22
20
  register_modifiers(
23
21
  # "sm:table-row-hover"
data/lib/daisy_ui/tabs.rb CHANGED
@@ -16,15 +16,20 @@ module DaisyUI
16
16
  def tab(*args, label: nil, **, &)
17
17
  # If first arg is a string, it's the label, rest are modifiers
18
18
  # Otherwise all args are modifiers
19
- if args.first.is_a?(String)
20
- label = args.shift
21
- end
19
+ label = args.shift if args.first.is_a?(String)
22
20
 
23
21
  render Tab.new(*args, label:, id:, **, &)
24
22
  end
25
23
 
26
24
  private
27
25
 
26
+ # Override Base#attributes to exclude :id from the main tabs container.
27
+ # The Tabs component uses :id internally to wire up the radio inputs
28
+ # and their associated content panels - NOT for the main container.
29
+ def attributes
30
+ options
31
+ end
32
+
28
33
  register_modifiers(
29
34
  # "sm:tabs-boxed"
30
35
  # "@sm:tabs-boxed"
@@ -36,7 +36,7 @@ module DaisyUI
36
36
  # Input always has just the theme-controller class
37
37
  input_classes = self.class.component_class.to_s
38
38
 
39
- attrs = {type: :checkbox, class: input_classes}
39
+ attrs = { type: :checkbox, class: input_classes }
40
40
  attrs[:value] = theme_value if theme_value
41
41
  attrs[:checked] = true if checked
42
42
  attrs.merge!(options)
@@ -48,7 +48,7 @@ module DaisyUI
48
48
  label(class: wrapper_classes) do
49
49
  public_send(as, **attrs)
50
50
  whitespace
51
- block.call
51
+ yield
52
52
  whitespace
53
53
  end
54
54
  else
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DaisyUI
4
- VERSION = "1.0.2"
4
+ VERSION = "1.0.3"
5
5
  end
data/lib/daisy_ui.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "phlex"
2
4
  require "zeitwerk"
3
5
  require_relative "daisy_ui/version"
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: daisyui
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mikael Henriksson
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-11-16 00:00:00.000000000 Z
10
+ date: 2025-11-17 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: phlex
@@ -136,6 +136,7 @@ metadata:
136
136
  source_code_uri: https://github.com/mhenrixon/daisy_ui
137
137
  changelog_uri: https://github.com/mhenrixon/daisy_ui/blob/main/CHANGELOG.md
138
138
  bug_tracker_uri: https://github.com/mhenrixon/daisy_ui/issues
139
+ rubygems_mfa_required: 'true'
139
140
  rdoc_options: []
140
141
  require_paths:
141
142
  - lib