loco_motion-rails 0.0.8 → 0.5.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.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +62 -14
  3. data/app/components/daisy/actions/button_component.html.haml +2 -2
  4. data/app/components/daisy/actions/button_component.rb +98 -59
  5. data/app/components/daisy/actions/dropdown_component.html.haml +1 -2
  6. data/app/components/daisy/actions/dropdown_component.rb +7 -10
  7. data/app/components/daisy/actions/modal_component.html.haml +10 -8
  8. data/app/components/daisy/actions/modal_component.rb +6 -6
  9. data/app/components/daisy/actions/swap_component.rb +13 -9
  10. data/app/components/daisy/actions/theme_controller.js +113 -0
  11. data/app/components/daisy/actions/theme_controller_component.rb +58 -17
  12. data/app/components/daisy/actions/theme_preview_component.html.haml +5 -0
  13. data/app/components/daisy/actions/theme_preview_component.rb +68 -0
  14. data/app/components/daisy/data_display/accordion_component.html.haml +0 -1
  15. data/app/components/daisy/data_display/accordion_component.rb +10 -3
  16. data/app/components/daisy/data_display/avatar_component.html.haml +1 -1
  17. data/app/components/daisy/data_display/avatar_component.rb +17 -7
  18. data/app/components/daisy/data_display/badge_component.rb +122 -4
  19. data/app/components/daisy/data_display/card_component.html.haml +1 -1
  20. data/app/components/daisy/data_display/card_component.rb +20 -6
  21. data/app/components/daisy/data_display/chat_component.rb +2 -2
  22. data/app/components/daisy/data_display/collapse_component.rb +9 -5
  23. data/app/components/daisy/data_display/countdown_component.rb +15 -5
  24. data/app/components/daisy/data_display/figure_component.rb +8 -3
  25. data/app/components/daisy/data_display/kbd_component.rb +13 -4
  26. data/app/components/daisy/data_display/list_component.html.haml +5 -0
  27. data/app/components/daisy/data_display/list_component.rb +82 -0
  28. data/app/components/daisy/data_display/list_item_component.rb +39 -0
  29. data/app/components/daisy/data_display/stat_component.html.haml +5 -6
  30. data/app/components/daisy/data_display/stat_component.rb +21 -8
  31. data/app/components/daisy/data_display/status_component.rb +47 -0
  32. data/app/components/daisy/data_display/timeline_component.rb +1 -1
  33. data/app/components/daisy/data_input/cally_component.html.haml +14 -0
  34. data/app/components/daisy/data_input/cally_component.rb +182 -0
  35. data/app/components/daisy/data_input/cally_input_component.html.haml +5 -0
  36. data/app/components/daisy/data_input/cally_input_component.rb +165 -0
  37. data/app/components/daisy/data_input/cally_input_controller.js +235 -0
  38. data/app/components/daisy/data_input/checkbox_component.html.haml +20 -0
  39. data/app/components/daisy/data_input/checkbox_component.rb +106 -0
  40. data/app/components/daisy/data_input/fieldset_component.html.haml +8 -0
  41. data/app/components/daisy/data_input/fieldset_component.rb +57 -0
  42. data/app/components/daisy/data_input/file_input_component.rb +98 -0
  43. data/app/components/daisy/data_input/filter_component.html.haml +3 -0
  44. data/app/components/daisy/data_input/filter_component.rb +221 -0
  45. data/app/components/daisy/data_input/label_component.rb +84 -0
  46. data/app/components/daisy/data_input/radio_button_component.rb +87 -0
  47. data/app/components/daisy/data_input/range_component.rb +95 -0
  48. data/app/components/daisy/data_input/rating_component.html.haml +11 -0
  49. data/app/components/daisy/data_input/rating_component.rb +139 -0
  50. data/app/components/daisy/data_input/select_component.html.haml +27 -0
  51. data/app/components/daisy/data_input/select_component.rb +320 -0
  52. data/app/components/daisy/data_input/text_area_component.rb +127 -0
  53. data/app/components/daisy/data_input/text_input_component.html.haml +27 -0
  54. data/app/components/daisy/data_input/text_input_component.rb +142 -0
  55. data/app/components/daisy/data_input/toggle_component.rb +48 -0
  56. data/app/components/daisy/feedback/alert_component.html.haml +1 -1
  57. data/app/components/daisy/feedback/alert_component.rb +86 -2
  58. data/app/components/daisy/feedback/loading_component.rb +10 -3
  59. data/app/components/daisy/feedback/skeleton_component.rb +1 -1
  60. data/app/components/daisy/layout/divider_component.rb +4 -2
  61. data/app/components/daisy/layout/drawer_component.html.haml +0 -1
  62. data/app/components/daisy/layout/footer_component.rb +6 -6
  63. data/app/components/daisy/mockup/device_component.rb +15 -18
  64. data/app/components/daisy/navigation/breadcrumbs_component.html.haml +0 -1
  65. data/app/components/daisy/navigation/breadcrumbs_component.rb +84 -9
  66. data/app/components/daisy/navigation/dock_component.rb +146 -0
  67. data/app/components/daisy/navigation/link_component.rb +18 -9
  68. data/app/components/daisy/navigation/menu_component.rb +15 -9
  69. data/app/components/daisy/navigation/navbar_component.html.haml +1 -1
  70. data/app/components/daisy/navigation/navbar_component.rb +2 -13
  71. data/app/components/daisy/navigation/steps_component.rb +6 -6
  72. data/app/components/daisy/navigation/tabs_component.html.haml +0 -1
  73. data/app/components/daisy/navigation/tabs_component.rb +26 -16
  74. data/app/components/hero/icon_component.rb +15 -5
  75. data/app/helpers/daisy/form_builder_helper.rb +186 -0
  76. data/app/views/examples/daisy/data_input/filters.html.haml +62 -0
  77. data/lib/daisy.rb +5 -0
  78. data/lib/hero.rb +1 -1
  79. data/lib/loco_motion/base_component.rb +53 -3
  80. data/lib/loco_motion/component_config.rb +1 -0
  81. data/lib/loco_motion/concerns/iconable_component.rb +134 -0
  82. data/lib/loco_motion/concerns/labelable_component.rb +142 -0
  83. data/lib/loco_motion/concerns/linkable_component.rb +40 -0
  84. data/lib/loco_motion/concerns/tippable_component.rb +25 -10
  85. data/lib/loco_motion/engine.rb +6 -0
  86. data/lib/loco_motion/helpers.rb +38 -17
  87. data/lib/loco_motion/patches/view_component/slot_loco_parent_patch.rb +37 -0
  88. data/lib/loco_motion/patches/view_component/slotable_default_patch.rb +21 -0
  89. data/lib/loco_motion/version.rb +1 -1
  90. data/lib/loco_motion.rb +12 -2
  91. metadata +93 -21
  92. data/app/components/daisy/actions/theme_controller_component.html.haml +0 -5
  93. data/app/components/daisy/layout/artboard_component.rb +0 -59
  94. data/app/components/daisy/navigation/bottom_nav_component.rb +0 -138
@@ -0,0 +1,320 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # The Select component provides a styled dropdown select input for forms.
5
+ # It supports various styling options, including sizes, colors, and variants.
6
+ # Additionally, it supports labelable functionality with start, end, and
7
+ # floating labels.
8
+ #
9
+ # @note Select inputs have a border by default and a width of 20rem. Use
10
+ # `select-ghost` to remove the border.
11
+ #
12
+ # @part placeholder The placeholder option element that is shown when no option
13
+ # is selected.
14
+ # @part label_wrapper The wrapper element for labels (when using
15
+ # start/end/floating labels).
16
+ # @part start The element that contains the start label (appears before the
17
+ # select).
18
+ # @part end The element that contains the end label (appears after the select).
19
+ # @part floating The element that contains the floating label (appears floating
20
+ # above the select).
21
+ #
22
+ # @slot options+ Custom options to be rendered in the select.
23
+ # @slot start Custom content for the start label.
24
+ # @slot end Custom content for the end label.
25
+ # @slot floating Custom content for the floating label.
26
+ #
27
+ # @loco_example Using simple strings for options
28
+ # = daisy_select(name: "size", css: "select-sm", options: ["Small", "Medium", "Large"])
29
+ #
30
+ # @loco_example Using a block to define options
31
+ # = daisy_select(name: "color", css: "select-primary") do |select|
32
+ # - select.with_option(value: "red", label: "Red")
33
+ # - select.with_option(value: "green", label: "Green")
34
+ # - select.with_option(value: "blue", label: "Blue")
35
+ #
36
+ # @loco_example With a start label
37
+ # = daisy_select(name: "color", start: "Select a color", options: ["Red", "Green", "Blue"])
38
+ #
39
+ # @loco_example With a floating label
40
+ # = daisy_select(name: "color", floating: "Color", options: ["Red", "Green", "Blue"])
41
+ #
42
+ class Daisy::DataInput::SelectComponent < LocoMotion::BaseComponent
43
+ include LocoMotion::Concerns::LabelableComponent
44
+
45
+ class SelectOptionComponent < LocoMotion::BasicComponent
46
+ attr_reader :value, :label, :selected, :disabled
47
+
48
+ #
49
+ # Initialize a new select option component.
50
+ #
51
+ # @param value [String, Symbol, Integer] The value of the option.
52
+ #
53
+ # @param label [String] The label to display for the option.
54
+ #
55
+ # @param selected [Boolean] Whether the option is selected. Defaults to false.
56
+ #
57
+ # @param disabled [Boolean] Whether the option is disabled. Defaults to false.
58
+ #
59
+ # @param css [String] CSS classes to apply to the option.
60
+ #
61
+ # @param html [Hash] HTML attributes to apply to the option.
62
+ #
63
+ def initialize(value:, label:, selected: false, disabled: false, css: "", html: {}, **kws)
64
+ @value = value
65
+ @label = label
66
+ @selected = selected
67
+ @disabled = disabled
68
+ @css = css
69
+ @html = html
70
+ super(**kws)
71
+ end
72
+
73
+ #
74
+ # Renders the option element with the appropriate attributes.
75
+ #
76
+ # @return [String] The rendered HTML for the option element.
77
+ #
78
+ def call
79
+ content_tag(:option, label, {
80
+ value: value,
81
+ selected: selected,
82
+ disabled: disabled,
83
+ class: @css
84
+ }.merge(@html))
85
+ end
86
+ end
87
+
88
+ renders_many :options, SelectOptionComponent
89
+
90
+ define_part :placeholder
91
+
92
+ attr_reader :name, :id, :value, :include_blank, :disabled, :required, :options_css, :options_html
93
+
94
+ #
95
+ # Initialize a new select component.
96
+ #
97
+ # @param kws [Hash] The keyword arguments for the component.
98
+ #
99
+ # @option kws name [String] The name attribute for the select input.
100
+ #
101
+ # @option kws id [String] The id attribute for the select input.
102
+ #
103
+ # @option kws value [String, Symbol, Integer] The current value of the select input.
104
+ # Determines which option is selected on initial render.
105
+ #
106
+ # @option kws include_blank [Boolean] Whether to include a blank option at the
107
+ # top of the list.
108
+ #
109
+ # @option kws disabled [Boolean] Whether the select input is disabled. Defaults to
110
+ # false.
111
+ #
112
+ # @option kws required [Boolean] Whether the select input is required for form
113
+ # validation. Defaults to false.
114
+ #
115
+ # @option kws options [Array] An array of options to display in the select input.
116
+ # Can be an array of strings or hashes with :value and :label keys.
117
+ #
118
+ # @option kws options_css [String] CSS classes to apply to each option.
119
+ #
120
+ # @option kws options_html [Hash] HTML attributes to apply to each option.
121
+ #
122
+ # @option kws option_label [Symbol] The key to use for the option label.
123
+ #
124
+ # @option kws option_value [Symbol] The key to use for the option value.
125
+ #
126
+ def initialize(**kws)
127
+ super(**kws)
128
+
129
+ @name = config_option(:name)
130
+ @id = config_option(:id)
131
+ @value = config_option(:value)
132
+ @include_blank = config_option(:include_blank, false)
133
+ @disabled = config_option(:disabled, false)
134
+ @required = config_option(:required, false)
135
+ @options_list = config_option(:options)
136
+ @options_css = config_option(:options_css, "")
137
+ @options_html = config_option(:options_html, {})
138
+ @option_label = config_option(:option_label, :label)
139
+ @option_value = config_option(:option_value, :value)
140
+ end
141
+
142
+ #
143
+ # Sets up the component before rendering.
144
+ #
145
+ def before_render
146
+ super
147
+
148
+ setup_component
149
+ setup_placeholder
150
+ end
151
+
152
+ #
153
+ # Sets up the component by configuring the tag name, CSS classes, and HTML attributes.
154
+ # Sets the tag to 'select' and adds the 'select' CSS class.
155
+ # Also adds Stimulus controller data attributes.
156
+ #
157
+ def setup_component
158
+ set_tag_name(:component, :select)
159
+
160
+ if has_floating_label?
161
+ add_css(:label_wrapper, "floating-label")
162
+ add_css(:component, "select")
163
+ elsif has_start_label? || has_end_label?
164
+ add_stimulus_controller(:label_wrapper, "select")
165
+
166
+ add_css(:label_wrapper, "select")
167
+ add_css(:start, "label")
168
+ add_css(:end, "label")
169
+ else
170
+ add_css(:component, "select")
171
+ end
172
+
173
+ # Add HTML attributes for the select element
174
+ add_html(:component,
175
+ name: @name,
176
+ id: @id,
177
+ disabled: @disabled,
178
+ required: @required
179
+ )
180
+ end
181
+
182
+ #
183
+ # Sets up the placeholder option that appears when no option is selected.
184
+ # Adds a disabled option with an empty value.
185
+ #
186
+ def setup_placeholder
187
+ set_tag_name(:placeholder, :option)
188
+ add_html(:placeholder, value: "", disabled: true, selected: @value.blank?)
189
+ end
190
+
191
+ #
192
+ # Converts the options array into SelectOptionComponent instances.
193
+ # Handles both hash options (with value/label keys) and simple string options.
194
+ #
195
+ # @return [Array<SelectOptionComponent>] Array of option components or empty array if @options_list is nil.
196
+ #
197
+ def default_options
198
+ return [] unless @options_list
199
+
200
+ options_list.map do |option|
201
+ value = extract_option_value(option)
202
+ label = extract_option_label(option, value)
203
+
204
+ Daisy::DataInput::SelectComponent::SelectOptionComponent.new(
205
+ value: value,
206
+ label: label,
207
+ selected: value.to_s == @value.to_s,
208
+ css: @options_css,
209
+ html: @options_html
210
+ )
211
+ end
212
+ end
213
+
214
+ private
215
+
216
+ # Extracts the value from an option using the configured @option_value key or method.
217
+ #
218
+ # @param option [Object] The option to extract the value from
219
+ # @return [Object] The extracted value
220
+ #
221
+ def extract_option_value(option)
222
+ if option.is_a?(Hash)
223
+ option[@option_value]
224
+ elsif option.respond_to?(@option_value)
225
+ option.public_send(@option_value)
226
+ else
227
+ option
228
+ end
229
+ end
230
+
231
+ # Extracts the label from an option using the configured @option_label key or method.
232
+ # Falls back to the value if no label can be extracted.
233
+ #
234
+ # @param option [Object] The option to extract the label from
235
+ # @param value [Object] The extracted value to use as fallback
236
+ # @return [String] The extracted label or string representation of the value
237
+ #
238
+ def extract_option_label(option, value)
239
+ if option.is_a?(Hash)
240
+ option[@option_label] || value.to_s
241
+ elsif option.respond_to?(@option_label)
242
+ option.public_send(@option_label)
243
+ else
244
+ value.to_s
245
+ end
246
+ end
247
+
248
+ # Alias for include_blank to match Ruby convention for boolean methods
249
+ def include_blank?
250
+ @include_blank
251
+ end
252
+
253
+ #
254
+ # Renders the select options based on the configuration.
255
+ # This method is used by the template to render options consistently.
256
+ #
257
+ # @return [String] The HTML for all options in the select.
258
+ #
259
+ def render_select_options
260
+ result = ""
261
+
262
+ # Add blank option if configured
263
+ if include_blank?
264
+ result += content_tag(:option, "", value: "")
265
+ end
266
+
267
+ # Add options from the block or default options
268
+ if options?
269
+ options.each do |option|
270
+ result += option.call
271
+ end
272
+ elsif default_options.present?
273
+ default_options.each do |option|
274
+ result += render(option)
275
+ end
276
+ end
277
+
278
+ result.html_safe
279
+ end
280
+
281
+ #
282
+ # Renders the component part with placeholder, options and content.
283
+ # This method is used by the template to render the select component consistently.
284
+ #
285
+ # @return [String] The HTML for the select component.
286
+ #
287
+ def render_component
288
+ part(:component) do
289
+ result = ""
290
+
291
+ # Add placeholder if provided
292
+ if @placeholder
293
+ result += part(:placeholder) do
294
+ @placeholder
295
+ end
296
+ end
297
+
298
+ # Add options
299
+ result += render_select_options
300
+
301
+ # Add content if present
302
+ if content?
303
+ result += (content || "")
304
+ end
305
+
306
+ result.html_safe
307
+ end
308
+ end
309
+
310
+ private
311
+
312
+ #
313
+ # Ensures the options list is always an array, even if a single option is provided.
314
+ #
315
+ # @return [Array] The list of options as an array.
316
+ #
317
+ def options_list
318
+ @options_list.is_a?(Array) ? @options_list : [@options_list]
319
+ end
320
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # The TextArea component renders a DaisyUI styled textarea field.
5
+ # It can be used standalone or with a form builder, and supports
6
+ # various styling options and states.
7
+ #
8
+ # @note Text areas have a border by default. Use `textarea-ghost` to remove the
9
+ # border.
10
+ #
11
+ # @part component The main textarea element that users can type into.
12
+ #
13
+ # @loco_example Basic Usage
14
+ # = daisy_text_area(name: "message", id: "message")
15
+ #
16
+ # @loco_example With Placeholder
17
+ # = daisy_text_area(name: "message", placeholder: "Enter your message here...")
18
+ #
19
+ # @loco_example With Initial Value
20
+ # = daisy_text_area(name: "message", value: "Initial text content")
21
+ #
22
+ # @loco_example With Specified Rows
23
+ # = daisy_text_area(name: "message", rows: 6)
24
+ #
25
+ # @loco_example Borderless Style
26
+ # = daisy_text_area(name: "message", css: "textarea-ghost")
27
+ #
28
+ # @loco_example Different Colors
29
+ # .flex.flex-col.gap-4
30
+ # = daisy_text_area(name: "primary", placeholder: "Primary", css: "textarea-primary")
31
+ # = daisy_text_area(name: "secondary", placeholder: "Secondary", css: "textarea-secondary")
32
+ # = daisy_text_area(name: "accent", placeholder: "Accent", css: "textarea-accent")
33
+ #
34
+ # @loco_example Disabled TextArea
35
+ # = daisy_text_area(name: "message", disabled: true)
36
+ #
37
+ # @loco_example Required TextArea
38
+ # = daisy_text_area(name: "message", required: true)
39
+ #
40
+ # @loco_example Readonly TextArea
41
+ # = daisy_text_area(name: "message", readonly: true, value: "This content cannot be edited.")
42
+ #
43
+ class Daisy::DataInput::TextAreaComponent < LocoMotion::BaseComponent
44
+ attr_reader :name, :id, :value, :placeholder, :rows, :cols, :disabled, :required, :readonly
45
+
46
+ #
47
+ # Instantiate a new TextArea component.
48
+ #
49
+ # @param kws [Hash] The keyword arguments for the component.
50
+ #
51
+ # @option kws name [String] The name attribute for the textarea.
52
+ #
53
+ # @option kws id [String] The ID attribute for the textarea.
54
+ #
55
+ # @option kws value [String] The initial value of the textarea.
56
+ #
57
+ # @option kws placeholder [String] Placeholder text for the textarea.
58
+ #
59
+ # @option kws rows [Integer] The number of visible text lines. Defaults to 4.
60
+ #
61
+ # @option kws cols [Integer] The visible width of the textarea. Defaults to nil.
62
+ #
63
+ # @option kws disabled [Boolean] Whether the textarea is disabled. Defaults to
64
+ # false.
65
+ #
66
+ # @option kws required [Boolean] Whether the textarea is required for form
67
+ # validation. Defaults to false.
68
+ #
69
+ # @option kws readonly [Boolean] Whether the textarea is read-only. Defaults to
70
+ # false.
71
+ #
72
+ def initialize(**kws)
73
+ super
74
+
75
+ @name = config_option(:name)
76
+ @id = config_option(:id)
77
+ @value = config_option(:value, nil)
78
+ @placeholder = config_option(:placeholder, nil)
79
+ @rows = config_option(:rows, 4)
80
+ @cols = config_option(:cols, nil)
81
+ @disabled = config_option(:disabled, false)
82
+ @required = config_option(:required, false)
83
+ @readonly = config_option(:readonly, false)
84
+ end
85
+
86
+ #
87
+ # Calls the {setup_component} method before rendering the component.
88
+ #
89
+ def before_render
90
+ setup_component
91
+ end
92
+
93
+ #
94
+ # Sets up the component by configuring the tag name, CSS classes, and HTML
95
+ # attributes. Sets the tag to textarea and adds the 'textarea' CSS class.
96
+ #
97
+ # This configures various attributes of the textarea including name, id, value,
98
+ # placeholder, rows, cols, and states like disabled, required, and readonly.
99
+ #
100
+ def setup_component
101
+ set_tag_name(:component, :textarea)
102
+
103
+ add_css(:component, "textarea")
104
+
105
+ add_html(:component, {
106
+ name: @name,
107
+ id: @id,
108
+ placeholder: @placeholder,
109
+ rows: @rows,
110
+ cols: @cols,
111
+ disabled: @disabled,
112
+ required: @required,
113
+ readonly: @readonly
114
+ })
115
+ end
116
+
117
+ #
118
+ # Renders the component with its value as content.
119
+ #
120
+ def call
121
+ if @value
122
+ part(:component) { @value }
123
+ else
124
+ part(:component)
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,27 @@
1
+ - if has_any_label?
2
+ = part(:label_wrapper) do
3
+ - if has_start_label?
4
+ - if start?
5
+ = start
6
+ - else
7
+ = part(:start) do
8
+ = @start
9
+
10
+ - if has_floating_label?
11
+ - if floating?
12
+ = floating
13
+ - else
14
+ = part(:floating) do
15
+ = @floating
16
+
17
+ = part(:component)
18
+
19
+ - if has_end_label?
20
+ - if end?
21
+ = self.send(:end)
22
+ - else
23
+ = part(:end) do
24
+ = @end
25
+
26
+ - else
27
+ = part(:component)
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # The TextInput component renders a DaisyUI styled text input field.
5
+ # It can be used standalone or with a form builder, and supports
6
+ # various styling options including different types, sizes and variants.
7
+ #
8
+ # @note Input fields have a border by default and a width of 20rem. Use
9
+ # `input-ghost` to remove the border.
10
+ #
11
+ # @part label_wrapper The wrapper element for labels (when using
12
+ # start/end/floating labels).
13
+ # @part start The element that contains the start label (appears before the
14
+ # input).
15
+ # @part end The element that contains the end label (appears after the input).
16
+ # @part floating The element that contains the floating label (appears floating
17
+ # above the input).
18
+ #
19
+ # @slot start Content to display before the input field.
20
+ # @slot end Content to display after the input field.
21
+ # @slot floating Custom content for the floating label.
22
+ #
23
+ # @loco_example Basic Usage
24
+ # = daisy_text_input(name: "username", id: "username")
25
+ #
26
+ # @loco_example With Placeholder
27
+ # = daisy_text_input(name: "email", id: "email", placeholder: "Enter your email")
28
+ #
29
+ # @loco_example Ghost Style (No Border)
30
+ # = daisy_text_input(name: "search", id: "search", css: "input-ghost")
31
+ #
32
+ # @loco_example Different Types
33
+ # = daisy_text_input(name: "password", id: "password", type: "password")
34
+ # = daisy_text_input(name: "email", id: "email", type: "email")
35
+ #
36
+ # @loco_example With Start Label
37
+ # = daisy_text_input(name: "username", id: "username", start: "Username:")
38
+ #
39
+ # @loco_example With End Label
40
+ # = daisy_text_input(name: "email", id: "email", end: "@example.com")
41
+ #
42
+ # @loco_example With Floating Label
43
+ # = daisy_text_input(name: "username", id: "username", floating: "Username")
44
+ #
45
+ # @loco_example With Icons
46
+ # = daisy_text_input(name: "search", placeholder: "Search...") do |text_input|
47
+ # - text_input.with_start do
48
+ # = hero_icon("magnifying-glass", size: 5, css: "text-gray-400")
49
+ #
50
+ # @loco_example With Start and End Content
51
+ # = daisy_text_input(name: "email", placeholder: "Email address") do |text_input|
52
+ # - text_input.with_start do
53
+ # = hero_icon("envelope", size: 5, css: "text-gray-400")
54
+ # - text_input.with_end do
55
+ # = daisy_button(title: "Verify", css: "h-full rounded-l-none")
56
+ #
57
+ # @loco_example Disabled Text Input
58
+ # = daisy_text_input(name: "username", id: "username", disabled: true)
59
+ #
60
+ class Daisy::DataInput::TextInputComponent < LocoMotion::BaseComponent
61
+ include LocoMotion::Concerns::LabelableComponent
62
+
63
+ attr_reader :name, :id, :value, :type, :disabled, :required, :readonly
64
+
65
+ #
66
+ # Instantiate a new TextInput component.
67
+ #
68
+ # @param kws [Hash] The keyword arguments for the component.
69
+ #
70
+ # @option kws name [String] The name attribute for the text input.
71
+ #
72
+ # @option kws id [String] The ID attribute for the text input.
73
+ #
74
+ # @option kws value [String] The initial value of the text input.
75
+ #
76
+ # @option kws type [String] The type of input (text, password, email, etc.).
77
+ # Defaults to "text".
78
+ #
79
+ # @option kws disabled [Boolean] Whether the text input is disabled. Defaults to
80
+ # false.
81
+ #
82
+ # @option kws required [Boolean] Whether the text input is required for form
83
+ # validation. Defaults to false.
84
+ #
85
+ # @option kws readonly [Boolean] Whether the text input is read-only. Defaults to
86
+ # false.
87
+ #
88
+ def initialize(**kws)
89
+ super
90
+
91
+ @name = config_option(:name)
92
+ @id = config_option(:id)
93
+ @value = config_option(:value, nil)
94
+ @type = config_option(:type, "text")
95
+ @disabled = config_option(:disabled, false)
96
+ @required = config_option(:required, false)
97
+ @readonly = config_option(:readonly, false)
98
+ @change = config_option(:change)
99
+ end
100
+
101
+ #
102
+ # Calls the {setup_component} method before rendering the component.
103
+ #
104
+ def before_render
105
+ super
106
+
107
+ setup_component
108
+ end
109
+
110
+ #
111
+ # Sets up the component by configuring the tag name, CSS classes, and HTML
112
+ # attributes. Sets the tag to input with appropriate type and adds the 'input'
113
+ # CSS class.
114
+ #
115
+ # This configures various attributes of the text input including name, id, value,
116
+ # placeholder, type, and states like disabled, required, and readonly.
117
+ #
118
+ def setup_component
119
+ set_tag_name(:component, :input)
120
+
121
+ if has_floating_label?
122
+ add_css(:label_wrapper, "floating-label input")
123
+ elsif has_start_label? || has_end_label?
124
+ add_css(:label_wrapper, "input")
125
+ else
126
+ add_css(:component, "input")
127
+ end
128
+
129
+ add_html(:component, {
130
+ type: @type,
131
+ name: @name,
132
+ id: @id,
133
+ value: @value,
134
+ placeholder: @placeholder,
135
+ disabled: @disabled,
136
+ required: @required,
137
+ readonly: @readonly
138
+ })
139
+
140
+ add_html(:component, { onchange: "document.getElementById('#{@change}').value = this.value" }) if @change
141
+ end
142
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # The Toggle component renders a DaisyUI styled toggle switch.
5
+ # It can be used standalone or with a form builder, and provides a visual way
6
+ # to toggle between two states (on/off).
7
+ #
8
+ # @part label_wrapper The wrapper element for labels (when using
9
+ # start/end/floating labels).
10
+ # @part start The element that contains the start label (appears before the
11
+ # toggle).
12
+ # @part end The element that contains the end label (appears after the toggle).
13
+ #
14
+ # @slot start Custom content for the start label.
15
+ # @slot end Custom content for the end label.
16
+ #
17
+ # @loco_example Basic Usage
18
+ # = daisy_toggle(name: "notifications", id: "notifications")
19
+ #
20
+ # @loco_example Checked Toggle
21
+ # = daisy_toggle(name: "notifications", id: "notifications", checked: true)
22
+ #
23
+ # @loco_example Colored Toggle
24
+ # = daisy_toggle(name: "theme", id: "theme", css: "toggle-primary", checked: true)
25
+ #
26
+ # @loco_example Disabled Toggle
27
+ # = daisy_toggle(name: "disabled", id: "disabled", disabled: true)
28
+ #
29
+ # @loco_example With End Label (common for toggles)
30
+ # = daisy_toggle(name: "notifications", id: "notifications", end: "Enable notifications")
31
+ #
32
+ class Daisy::DataInput::ToggleComponent < Daisy::DataInput::CheckboxComponent
33
+ #
34
+ # Instantiate a new Toggle component.
35
+ #
36
+ # This component accepts the same options as {Daisy::DataInput::CheckboxComponent},
37
+ # but always sets `toggle: true` to render the checkbox as a toggle switch.
38
+ #
39
+ # @param kws [Hash] The keyword arguments for the component. See
40
+ # {Daisy::DataInput::CheckboxComponent#initialize} for available options.
41
+ #
42
+ def initialize(**kws)
43
+ # Always force toggle to be true
44
+ kws[:toggle] = true
45
+
46
+ super(**kws)
47
+ end
48
+ end
@@ -1,7 +1,7 @@
1
1
  = part(:component) do
2
2
  - # If we have an icon, assume we want to wrap the content
3
3
  - if @icon.present?
4
- = hero_icon(@icon, **rendered_html(:icon))
4
+ = render_icon
5
5
  = part(:content_wrapper) do
6
6
  = content
7
7
  - else