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.
- checksums.yaml +4 -4
- data/README.md +62 -14
- data/app/components/daisy/actions/button_component.html.haml +2 -2
- data/app/components/daisy/actions/button_component.rb +98 -59
- data/app/components/daisy/actions/dropdown_component.html.haml +1 -2
- data/app/components/daisy/actions/dropdown_component.rb +7 -10
- data/app/components/daisy/actions/modal_component.html.haml +10 -8
- data/app/components/daisy/actions/modal_component.rb +6 -6
- data/app/components/daisy/actions/swap_component.rb +13 -9
- data/app/components/daisy/actions/theme_controller.js +113 -0
- data/app/components/daisy/actions/theme_controller_component.rb +58 -17
- data/app/components/daisy/actions/theme_preview_component.html.haml +5 -0
- data/app/components/daisy/actions/theme_preview_component.rb +68 -0
- data/app/components/daisy/data_display/accordion_component.html.haml +0 -1
- data/app/components/daisy/data_display/accordion_component.rb +10 -3
- data/app/components/daisy/data_display/avatar_component.html.haml +1 -1
- data/app/components/daisy/data_display/avatar_component.rb +17 -7
- data/app/components/daisy/data_display/badge_component.rb +122 -4
- data/app/components/daisy/data_display/card_component.html.haml +1 -1
- data/app/components/daisy/data_display/card_component.rb +20 -6
- data/app/components/daisy/data_display/chat_component.rb +2 -2
- data/app/components/daisy/data_display/collapse_component.rb +9 -5
- data/app/components/daisy/data_display/countdown_component.rb +15 -5
- data/app/components/daisy/data_display/figure_component.rb +8 -3
- data/app/components/daisy/data_display/kbd_component.rb +13 -4
- data/app/components/daisy/data_display/list_component.html.haml +5 -0
- data/app/components/daisy/data_display/list_component.rb +82 -0
- data/app/components/daisy/data_display/list_item_component.rb +39 -0
- data/app/components/daisy/data_display/stat_component.html.haml +5 -6
- data/app/components/daisy/data_display/stat_component.rb +21 -8
- data/app/components/daisy/data_display/status_component.rb +47 -0
- data/app/components/daisy/data_display/timeline_component.rb +1 -1
- data/app/components/daisy/data_input/cally_component.html.haml +14 -0
- data/app/components/daisy/data_input/cally_component.rb +182 -0
- data/app/components/daisy/data_input/cally_input_component.html.haml +5 -0
- data/app/components/daisy/data_input/cally_input_component.rb +165 -0
- data/app/components/daisy/data_input/cally_input_controller.js +235 -0
- data/app/components/daisy/data_input/checkbox_component.html.haml +20 -0
- data/app/components/daisy/data_input/checkbox_component.rb +106 -0
- data/app/components/daisy/data_input/fieldset_component.html.haml +8 -0
- data/app/components/daisy/data_input/fieldset_component.rb +57 -0
- data/app/components/daisy/data_input/file_input_component.rb +98 -0
- data/app/components/daisy/data_input/filter_component.html.haml +3 -0
- data/app/components/daisy/data_input/filter_component.rb +221 -0
- data/app/components/daisy/data_input/label_component.rb +84 -0
- data/app/components/daisy/data_input/radio_button_component.rb +87 -0
- data/app/components/daisy/data_input/range_component.rb +95 -0
- data/app/components/daisy/data_input/rating_component.html.haml +11 -0
- data/app/components/daisy/data_input/rating_component.rb +139 -0
- data/app/components/daisy/data_input/select_component.html.haml +27 -0
- data/app/components/daisy/data_input/select_component.rb +320 -0
- data/app/components/daisy/data_input/text_area_component.rb +127 -0
- data/app/components/daisy/data_input/text_input_component.html.haml +27 -0
- data/app/components/daisy/data_input/text_input_component.rb +142 -0
- data/app/components/daisy/data_input/toggle_component.rb +48 -0
- data/app/components/daisy/feedback/alert_component.html.haml +1 -1
- data/app/components/daisy/feedback/alert_component.rb +86 -2
- data/app/components/daisy/feedback/loading_component.rb +10 -3
- data/app/components/daisy/feedback/skeleton_component.rb +1 -1
- data/app/components/daisy/layout/divider_component.rb +4 -2
- data/app/components/daisy/layout/drawer_component.html.haml +0 -1
- data/app/components/daisy/layout/footer_component.rb +6 -6
- data/app/components/daisy/mockup/device_component.rb +15 -18
- data/app/components/daisy/navigation/breadcrumbs_component.html.haml +0 -1
- data/app/components/daisy/navigation/breadcrumbs_component.rb +84 -9
- data/app/components/daisy/navigation/dock_component.rb +146 -0
- data/app/components/daisy/navigation/link_component.rb +18 -9
- data/app/components/daisy/navigation/menu_component.rb +15 -9
- data/app/components/daisy/navigation/navbar_component.html.haml +1 -1
- data/app/components/daisy/navigation/navbar_component.rb +2 -13
- data/app/components/daisy/navigation/steps_component.rb +6 -6
- data/app/components/daisy/navigation/tabs_component.html.haml +0 -1
- data/app/components/daisy/navigation/tabs_component.rb +26 -16
- data/app/components/hero/icon_component.rb +15 -5
- data/app/helpers/daisy/form_builder_helper.rb +186 -0
- data/app/views/examples/daisy/data_input/filters.html.haml +62 -0
- data/lib/daisy.rb +5 -0
- data/lib/hero.rb +1 -1
- data/lib/loco_motion/base_component.rb +53 -3
- data/lib/loco_motion/component_config.rb +1 -0
- data/lib/loco_motion/concerns/iconable_component.rb +134 -0
- data/lib/loco_motion/concerns/labelable_component.rb +142 -0
- data/lib/loco_motion/concerns/linkable_component.rb +40 -0
- data/lib/loco_motion/concerns/tippable_component.rb +25 -10
- data/lib/loco_motion/engine.rb +6 -0
- data/lib/loco_motion/helpers.rb +38 -17
- data/lib/loco_motion/patches/view_component/slot_loco_parent_patch.rb +37 -0
- data/lib/loco_motion/patches/view_component/slotable_default_patch.rb +21 -0
- data/lib/loco_motion/version.rb +1 -1
- data/lib/loco_motion.rb +12 -2
- metadata +93 -21
- data/app/components/daisy/actions/theme_controller_component.html.haml +0 -5
- data/app/components/daisy/layout/artboard_component.rb +0 -59
- data/app/components/daisy/navigation/bottom_nav_component.rb +0 -138
@@ -0,0 +1,221 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# The Filter component is a group of radio buttons where choosing one option
|
5
|
+
# hides the others and shows a reset button.
|
6
|
+
#
|
7
|
+
# @loco_example Basic Usage
|
8
|
+
# = daisy_filter(name: "frameworks", options: ["Svelte", "Vue", "React"])
|
9
|
+
#
|
10
|
+
# @loco_example Using Hash Options
|
11
|
+
# = daisy_filter(name: "languages", options: [
|
12
|
+
# { label: "Ruby", value: "ruby" },
|
13
|
+
# { label: "JavaScript", value: "js" },
|
14
|
+
# { label: "Python", value: "py" }
|
15
|
+
# ])
|
16
|
+
#
|
17
|
+
# @loco_example Custom Styling
|
18
|
+
# = daisy_filter(name: "priorities", css: "items-center") do |f|
|
19
|
+
# - f.with_reset_button(css: "btn-accent btn-sm rounded-full")
|
20
|
+
# - f.with_option(label: "Low", css: "btn-outline btn-success")
|
21
|
+
# - f.with_option(label: "Medium", css: "btn-outline btn-warning")
|
22
|
+
# - f.with_option(label: "High", css: "btn-outline btn-error")
|
23
|
+
#
|
24
|
+
# @loco_example Within Form Builder
|
25
|
+
# = form_with(model: @post) do |form|
|
26
|
+
# = form.daisy_filter(:category, options: ["News", "Tech", "Sports"])
|
27
|
+
# = form.submit "Save", class: "btn btn-primary mt-4"
|
28
|
+
#
|
29
|
+
# @loco_example Form Builder With Block
|
30
|
+
# = form_with(model: @user) do |form|
|
31
|
+
# = form.daisy_filter(:role) do |f|
|
32
|
+
# - f.with_option(label: "Admin", value: "admin")
|
33
|
+
# - f.with_option(label: "Editor", value: "editor")
|
34
|
+
# - f.with_option(label: "Viewer", value: "viewer")
|
35
|
+
# = form.submit "Update", class: "btn btn-primary mt-4"
|
36
|
+
#
|
37
|
+
module Daisy
|
38
|
+
module DataInput
|
39
|
+
class FilterComponent < LocoMotion::BaseComponent
|
40
|
+
class FilterOptionComponent < Daisy::DataInput::RadioButtonComponent
|
41
|
+
#
|
42
|
+
# Initialize a new filter option component.
|
43
|
+
#
|
44
|
+
# @param kws [Hash] The keyword arguments for the component.
|
45
|
+
#
|
46
|
+
# @option kws label [String] The aria-label for the radio button.
|
47
|
+
#
|
48
|
+
def initialize(**kws)
|
49
|
+
super(**kws)
|
50
|
+
|
51
|
+
@label = config_option(:label)
|
52
|
+
@index = config_option(:index)
|
53
|
+
@skip_styling = true
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# Setup the component before rendering.
|
58
|
+
#
|
59
|
+
def before_render
|
60
|
+
# Make sure to pull the default name from the parent
|
61
|
+
@name = config_option(:name, loco_parent.name)
|
62
|
+
@id = config_option(:id, "#{loco_parent.id}_#{@index}")
|
63
|
+
|
64
|
+
# Call the parent setup first
|
65
|
+
super
|
66
|
+
|
67
|
+
# Add btn class for styling
|
68
|
+
add_css(:component, "btn")
|
69
|
+
add_html(:component, { id: @id })
|
70
|
+
|
71
|
+
# Add aria-label if specified
|
72
|
+
if @label.present?
|
73
|
+
add_html(:component, { "aria-label": @label })
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class FilterResetComponent < Daisy::DataInput::RadioButtonComponent
|
79
|
+
#
|
80
|
+
# Initialize a new filter reset component.
|
81
|
+
#
|
82
|
+
# @param kws [Hash] The keyword arguments for the component.
|
83
|
+
#
|
84
|
+
# @option kws disabled [Boolean] Whether the reset button is disabled. Defaults to false.
|
85
|
+
#
|
86
|
+
def initialize(**kws)
|
87
|
+
super(**kws)
|
88
|
+
|
89
|
+
@skip_styling = true
|
90
|
+
end
|
91
|
+
|
92
|
+
#
|
93
|
+
# Setup the component before rendering.
|
94
|
+
#
|
95
|
+
def before_render
|
96
|
+
# Make sure to pull the default name from the parent
|
97
|
+
@name = config_option(:name, loco_parent.name)
|
98
|
+
@id = config_option(:id, "#{loco_parent.id}_reset")
|
99
|
+
|
100
|
+
# Call parent setup first
|
101
|
+
super
|
102
|
+
|
103
|
+
# Add square styling
|
104
|
+
add_css(:component, "where:btn where:btn-square filter-reset")
|
105
|
+
|
106
|
+
# Set type to reset
|
107
|
+
add_html(:component, { type: "radio", id: @id })
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
include ViewComponent::SlotableDefault
|
112
|
+
|
113
|
+
renders_one :reset_button, FilterResetComponent
|
114
|
+
renders_many :options, FilterOptionComponent
|
115
|
+
|
116
|
+
attr_reader :name, :id
|
117
|
+
|
118
|
+
#
|
119
|
+
# Initialize a new filter component.
|
120
|
+
#
|
121
|
+
# @param kws [Hash] The keyword arguments for the component.
|
122
|
+
#
|
123
|
+
# @option kws name [String] Required name attribute for the radio button group.
|
124
|
+
#
|
125
|
+
# @option kws options [Array] An array of options to display in the filter.
|
126
|
+
# Can be an array of strings, symbols, or hashes with :label keys.
|
127
|
+
#
|
128
|
+
# @option kws value [String] The current value of the filter (for form integration).
|
129
|
+
#
|
130
|
+
def initialize(**kws)
|
131
|
+
super(**kws)
|
132
|
+
|
133
|
+
@name = config_option(:name)
|
134
|
+
@id = config_option(:id, SecureRandom.uuid)
|
135
|
+
@options_list = config_option(:options)
|
136
|
+
@value = config_option(:value)
|
137
|
+
end
|
138
|
+
|
139
|
+
#
|
140
|
+
# Setup the component before rendering.
|
141
|
+
#
|
142
|
+
def before_render
|
143
|
+
super
|
144
|
+
|
145
|
+
setup_component
|
146
|
+
end
|
147
|
+
|
148
|
+
def default_reset_button
|
149
|
+
FilterResetComponent.new(name: @name)
|
150
|
+
end
|
151
|
+
|
152
|
+
#
|
153
|
+
# Converts the options array into FilterOptionComponent instances.
|
154
|
+
# Handles both hash options (with label keys) and simple string/symbol options.
|
155
|
+
#
|
156
|
+
# @return [Array<FilterOptionComponent>] Array of option components or empty array if @options_list is nil.
|
157
|
+
#
|
158
|
+
def standard_options
|
159
|
+
return [] unless options_list
|
160
|
+
|
161
|
+
options_list.map.with_index do |option, index|
|
162
|
+
label = option.is_a?(Hash) ? option[:label] : option.to_s
|
163
|
+
value = option.is_a?(Hash) ? option[:value] : option
|
164
|
+
|
165
|
+
# Check if this option should be selected based on the component's value
|
166
|
+
checked = @value.present? && @value.to_s == value.to_s
|
167
|
+
|
168
|
+
Daisy::DataInput::FilterComponent::FilterOptionComponent.new(
|
169
|
+
loco_parent: component_ref,
|
170
|
+
name: @name,
|
171
|
+
label: label,
|
172
|
+
value: value,
|
173
|
+
checked: checked,
|
174
|
+
index: index.to_s # Ensure index is a string
|
175
|
+
)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
#
|
180
|
+
# Renders the filter options based on the configuration.
|
181
|
+
# This method is used by the template to render options consistently.
|
182
|
+
#
|
183
|
+
# @return [String] The HTML for all options in the filter.
|
184
|
+
#
|
185
|
+
def render_filter_options
|
186
|
+
result = ""
|
187
|
+
|
188
|
+
if options?
|
189
|
+
options.each do |option|
|
190
|
+
result += render(option)
|
191
|
+
end
|
192
|
+
elsif standard_options.present?
|
193
|
+
standard_options.each do |option|
|
194
|
+
result += render(option)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
result.html_safe
|
199
|
+
end
|
200
|
+
|
201
|
+
private
|
202
|
+
|
203
|
+
#
|
204
|
+
# Sets up the component by configuring the tag name, CSS classes, and HTML attributes.
|
205
|
+
#
|
206
|
+
def setup_component
|
207
|
+
# Add base component class
|
208
|
+
add_css(:component, "filter")
|
209
|
+
end
|
210
|
+
|
211
|
+
#
|
212
|
+
# Ensures the options list is always an array, even if a single option is provided.
|
213
|
+
#
|
214
|
+
# @return [Array] The list of options as an array.
|
215
|
+
#
|
216
|
+
def options_list
|
217
|
+
[@options_list].flatten.compact
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# The Label component renders a DaisyUI styled label for form inputs.
|
5
|
+
# It can be used with any form input component and provides visual styling
|
6
|
+
# consistent with other Daisy UI elements.
|
7
|
+
#
|
8
|
+
# @loco_example Basic Usage
|
9
|
+
# = daisy_label(for: "input_id") do
|
10
|
+
# My Label
|
11
|
+
#
|
12
|
+
# @loco_example With Label Title
|
13
|
+
# = daisy_label(for: "input_id", title: "My Label")
|
14
|
+
#
|
15
|
+
# @loco_example Required Label
|
16
|
+
# = daisy_label(for: "input_id", required: true) do
|
17
|
+
# My Required Label
|
18
|
+
#
|
19
|
+
class Daisy::DataInput::LabelComponent < LocoMotion::BaseComponent
|
20
|
+
attr_reader :for, :title, :required
|
21
|
+
|
22
|
+
#
|
23
|
+
# Instantiate a new Label component.
|
24
|
+
#
|
25
|
+
# @param kws [Hash] The keyword arguments for the component.
|
26
|
+
#
|
27
|
+
# @option kws for [String] The ID of the input element this label is for.
|
28
|
+
# This connects the label to its associated form control for accessibility.
|
29
|
+
#
|
30
|
+
# @option kws title [String] The text content of the label. If not provided,
|
31
|
+
# the content block will be used. If a content block is provided, it will
|
32
|
+
# take precedence over the title option.
|
33
|
+
#
|
34
|
+
# @option kws required [Boolean] Whether the label is for a required input.
|
35
|
+
# Defaults to false.
|
36
|
+
#
|
37
|
+
def initialize(title = nil, **kws)
|
38
|
+
super
|
39
|
+
|
40
|
+
@for = config_option(:for)
|
41
|
+
@title = config_option(:title, title)
|
42
|
+
@required = config_option(:required, false)
|
43
|
+
end
|
44
|
+
|
45
|
+
#
|
46
|
+
# Calls the {setup_component} method before rendering the component.
|
47
|
+
#
|
48
|
+
def before_render
|
49
|
+
setup_component
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Sets up the component by configuring the tag name, CSS classes, and HTML
|
54
|
+
# attributes. Sets the tag to 'label' and adds the 'label' CSS class.
|
55
|
+
#
|
56
|
+
# This configures the 'for' attribute to connect the label to its input and
|
57
|
+
# adds appropriate styling for required inputs when needed.
|
58
|
+
#
|
59
|
+
def setup_component
|
60
|
+
set_tag_name(:component, :label)
|
61
|
+
|
62
|
+
add_css(:component, "label")
|
63
|
+
|
64
|
+
add_html(:component, {
|
65
|
+
for: @for
|
66
|
+
})
|
67
|
+
end
|
68
|
+
|
69
|
+
#
|
70
|
+
# Renders the component with its content.
|
71
|
+
#
|
72
|
+
def call
|
73
|
+
part(:component) do
|
74
|
+
if content?
|
75
|
+
content
|
76
|
+
elsif @title
|
77
|
+
content_tag(:span, @title, class: "label-text")
|
78
|
+
else
|
79
|
+
# Fallback to empty content
|
80
|
+
""
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# The Radio Button component renders a DaisyUI styled radio button input.
|
5
|
+
# It can be used standalone or with a form builder, and is ideal for creating
|
6
|
+
# option groups where users must select exactly one choice.
|
7
|
+
#
|
8
|
+
# @loco_example Basic Usage
|
9
|
+
# = daisy_radio(name: "option", id: "option1", value: "1")
|
10
|
+
#
|
11
|
+
# @loco_example Checked Radio Button
|
12
|
+
# = daisy_radio(name: "option", id: "option2", value: "2", checked: true)
|
13
|
+
#
|
14
|
+
# @loco_example Disabled Radio Button
|
15
|
+
# = daisy_radio(name: "option", id: "option3", value: "3", disabled: true)
|
16
|
+
#
|
17
|
+
class Daisy::DataInput::RadioButtonComponent < LocoMotion::BaseComponent
|
18
|
+
attr_reader :name, :id, :value, :checked, :disabled, :required
|
19
|
+
|
20
|
+
#
|
21
|
+
# Instantiate a new Radio Button component.
|
22
|
+
#
|
23
|
+
# @param kws [Hash] The keyword arguments for the component.
|
24
|
+
#
|
25
|
+
# @option kws name [String] The name attribute for the radio button input.
|
26
|
+
#
|
27
|
+
# @option kws id [String] The ID attribute for the radio button input.
|
28
|
+
#
|
29
|
+
# @option kws value [String] The value attribute for the radio button input.
|
30
|
+
#
|
31
|
+
# @option kws checked [Boolean] Whether the radio button is checked. Defaults to
|
32
|
+
# false.
|
33
|
+
#
|
34
|
+
# @option kws disabled [Boolean] Whether the radio button is disabled. Defaults to
|
35
|
+
# false.
|
36
|
+
#
|
37
|
+
# @option kws required [Boolean] Whether the radio button is required for form
|
38
|
+
# validation. Defaults to false.
|
39
|
+
#
|
40
|
+
def initialize(**kws)
|
41
|
+
super
|
42
|
+
|
43
|
+
@name = config_option(:name)
|
44
|
+
@id = config_option(:id)
|
45
|
+
@value = config_option(:value)
|
46
|
+
@checked = config_option(:checked, false)
|
47
|
+
@disabled = config_option(:disabled, false)
|
48
|
+
@required = config_option(:required, false)
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
# Calls the {setup_component} method before rendering the component.
|
53
|
+
#
|
54
|
+
def before_render
|
55
|
+
setup_component
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
# Sets up the component by configuring the tag name, CSS classes, and HTML
|
60
|
+
# attributes. Sets the tag to input with type 'radio' and adds the 'radio' CSS class.
|
61
|
+
#
|
62
|
+
# This configures the name, id, value, disabled state, required state, and
|
63
|
+
# checked state of the radio button.
|
64
|
+
#
|
65
|
+
def setup_component
|
66
|
+
set_tag_name(:component, :input)
|
67
|
+
|
68
|
+
add_css(:component, "radio") unless @skip_styling
|
69
|
+
|
70
|
+
add_html(:component, {
|
71
|
+
type: "radio",
|
72
|
+
name: @name,
|
73
|
+
id: @id,
|
74
|
+
value: @value,
|
75
|
+
checked: @checked,
|
76
|
+
disabled: @disabled,
|
77
|
+
required: @required
|
78
|
+
})
|
79
|
+
end
|
80
|
+
|
81
|
+
#
|
82
|
+
# Renders the component inline with no additional whitespace.
|
83
|
+
#
|
84
|
+
def call
|
85
|
+
part(:component)
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# The Range component renders a DaisyUI styled range input slider.
|
5
|
+
# It can be used standalone or with a form builder, and supports customization
|
6
|
+
# of min/max values, step increments, and color variants.
|
7
|
+
#
|
8
|
+
# @loco_example Basic Usage
|
9
|
+
# = daisy_range(name: "volume", id: "volume", min: 0, max: 100, value: 50)
|
10
|
+
#
|
11
|
+
# @loco_example Range with Steps
|
12
|
+
# = daisy_range(name: "step_range", id: "step_range", min: 0, max: 100, step: 25)
|
13
|
+
#
|
14
|
+
# @loco_example Range with Different Colors
|
15
|
+
# = daisy_range(name: "primary_range", id: "primary_range", css: "range-primary")
|
16
|
+
# = daisy_range(name: "error_range", id: "error_range", css: "range-error")
|
17
|
+
#
|
18
|
+
class Daisy::DataInput::RangeComponent < LocoMotion::BaseComponent
|
19
|
+
attr_reader :name, :id, :min, :max, :step, :value, :disabled, :required
|
20
|
+
|
21
|
+
#
|
22
|
+
# Instantiate a new Range component.
|
23
|
+
#
|
24
|
+
# @param kws [Hash] The keyword arguments for the component.
|
25
|
+
#
|
26
|
+
# @option kws name [String] The name attribute for the range input.
|
27
|
+
#
|
28
|
+
# @option kws id [String] The ID attribute for the range input.
|
29
|
+
#
|
30
|
+
# @option kws min [Integer] The minimum value (default: 0).
|
31
|
+
#
|
32
|
+
# @option kws max [Integer] The maximum value (default: 100).
|
33
|
+
#
|
34
|
+
# @option kws step [Integer] The step increment (default: 1).
|
35
|
+
#
|
36
|
+
# @option kws value [Integer] The current value (default: min).
|
37
|
+
#
|
38
|
+
# @option kws disabled [Boolean] Whether the range input is disabled. Defaults to
|
39
|
+
# false.
|
40
|
+
#
|
41
|
+
# @option kws required [Boolean] Whether the range input is required for form
|
42
|
+
# validation. Defaults to false.
|
43
|
+
#
|
44
|
+
def initialize(**kws)
|
45
|
+
super
|
46
|
+
|
47
|
+
@name = config_option(:name)
|
48
|
+
@id = config_option(:id)
|
49
|
+
@min = config_option(:min, 0)
|
50
|
+
@max = config_option(:max, 100)
|
51
|
+
@step = config_option(:step, 1)
|
52
|
+
@value = config_option(:value, @min)
|
53
|
+
@disabled = config_option(:disabled, false)
|
54
|
+
@required = config_option(:required, false)
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Calls the {setup_component} method before rendering the component.
|
59
|
+
#
|
60
|
+
def before_render
|
61
|
+
setup_component
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# Sets up the component by configuring the tag name, CSS classes, and HTML
|
66
|
+
# attributes. Sets the tag to input with type 'range' and adds the 'range' CSS class.
|
67
|
+
#
|
68
|
+
# This configures the min, max, step values along with name, id, value, disabled state,
|
69
|
+
# and required state of the range input.
|
70
|
+
#
|
71
|
+
def setup_component
|
72
|
+
set_tag_name(:component, :input)
|
73
|
+
|
74
|
+
add_css(:component, "range")
|
75
|
+
|
76
|
+
add_html(:component, {
|
77
|
+
type: "range",
|
78
|
+
name: @name,
|
79
|
+
id: @id,
|
80
|
+
min: @min,
|
81
|
+
max: @max,
|
82
|
+
step: @step,
|
83
|
+
value: @value,
|
84
|
+
disabled: @disabled,
|
85
|
+
required: @required
|
86
|
+
})
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# Renders the component inline with no additional whitespace.
|
91
|
+
#
|
92
|
+
def call
|
93
|
+
part(:component)
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# The Rating component renders a DaisyUI styled rating input using radio buttons.
|
5
|
+
# It can be used standalone or with a form builder, allowing users to select a
|
6
|
+
# rating from 1 to a configurable maximum value. Supports customization of size,
|
7
|
+
# colors, and initial value.
|
8
|
+
#
|
9
|
+
# @loco_example Basic Usage
|
10
|
+
# = daisy_rating(name: "product_rating", id: "product_rating")
|
11
|
+
#
|
12
|
+
# @loco_example Disabled Rating
|
13
|
+
# = daisy_rating(name: "disabled_rating", value: 3, disabled: true)
|
14
|
+
#
|
15
|
+
# @loco_example Rating with Different Colors
|
16
|
+
# = daisy_rating(name: "primary_rating", css: "[&>input]:bg-primary")
|
17
|
+
# = daisy_rating(name: "warning_rating", css: "[&>input]:bg-warning")
|
18
|
+
#
|
19
|
+
# @loco_example Rating with Different Sizes
|
20
|
+
# = daisy_rating(name: "small_rating", css: "rating-sm")
|
21
|
+
# = daisy_rating(name: "large_rating", css: "rating-lg")
|
22
|
+
#
|
23
|
+
class Daisy::DataInput::RatingComponent < LocoMotion::BaseComponent
|
24
|
+
#
|
25
|
+
# Inner component for rendering individual rating items as radio inputs.
|
26
|
+
#
|
27
|
+
class RatingItemComponent < LocoMotion::BasicComponent
|
28
|
+
#
|
29
|
+
# Sets up the component before rendering.
|
30
|
+
#
|
31
|
+
def before_render
|
32
|
+
set_tag_name(:component, :input)
|
33
|
+
add_html(:component, { name: loco_parent.name, type: "radio" })
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Renders the component with the appropriate attributes.
|
38
|
+
# Takes the name from the parent component and sets the type to radio.
|
39
|
+
#
|
40
|
+
# @return [String] The rendered HTML for the rating item.
|
41
|
+
#
|
42
|
+
def call
|
43
|
+
part(:component)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
define_part :hidden_input
|
48
|
+
|
49
|
+
renders_many :items, RatingItemComponent
|
50
|
+
|
51
|
+
attr_reader :name, :value, :max, :disabled, :required, :id, :inputs_css, :inputs_html
|
52
|
+
|
53
|
+
#
|
54
|
+
# Instantiate a new Rating component.
|
55
|
+
#
|
56
|
+
# @param kws [Hash] The keyword arguments for the component.
|
57
|
+
#
|
58
|
+
# @option kws name [String] The name attribute for the radio inputs.
|
59
|
+
#
|
60
|
+
# @option kws value [Integer] The current rating value.
|
61
|
+
#
|
62
|
+
# @option kws max [Integer] The maximum rating value (default: 5).
|
63
|
+
#
|
64
|
+
# @option kws disabled [Boolean] Whether the rating is disabled. Defaults to
|
65
|
+
# false. When disabled, users cannot interact with the rating control.
|
66
|
+
#
|
67
|
+
# @option kws required [Boolean] Whether the rating input is required for form
|
68
|
+
# validation. Defaults to false.
|
69
|
+
#
|
70
|
+
# @option kws id [String] The ID for the first radio input.
|
71
|
+
#
|
72
|
+
# @option kws inputs_css [String] CSS classes to apply to each rating input.
|
73
|
+
#
|
74
|
+
# @option kws inputs_html [Hash] HTML attributes to apply to each rating input.
|
75
|
+
#
|
76
|
+
def initialize(**kws)
|
77
|
+
super
|
78
|
+
|
79
|
+
@name = config_option(:name)
|
80
|
+
@value = config_option(:value)
|
81
|
+
@max = config_option(:max, 5)
|
82
|
+
@disabled = config_option(:disabled, false)
|
83
|
+
@required = config_option(:required, false)
|
84
|
+
@id = config_option(:id)
|
85
|
+
@inputs_css = config_option(:inputs_css)
|
86
|
+
@inputs_html = config_option(:inputs_html, {})
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# Calls the {setup_component} and {setup_hidden_input} methods before rendering
|
91
|
+
# the component. This prepares the rating container and creates a hidden input
|
92
|
+
# if needed.
|
93
|
+
#
|
94
|
+
def before_render
|
95
|
+
setup_component
|
96
|
+
setup_hidden_input
|
97
|
+
end
|
98
|
+
|
99
|
+
#
|
100
|
+
# Sets up the component by configuring the tag name and CSS classes.
|
101
|
+
#
|
102
|
+
def setup_component
|
103
|
+
set_tag_name(:component, :div)
|
104
|
+
add_css(:component, "rating")
|
105
|
+
add_html(:component, id: @id) if @id
|
106
|
+
end
|
107
|
+
|
108
|
+
#
|
109
|
+
# Sets up a hidden input so that the rating can start empty.
|
110
|
+
#
|
111
|
+
def setup_hidden_input
|
112
|
+
set_tag_name(:hidden_input, :input)
|
113
|
+
add_css(:hidden_input, "hidden")
|
114
|
+
add_html(:hidden_input, { type: "radio", name: @name, value: nil, checked: @value.blank? })
|
115
|
+
end
|
116
|
+
|
117
|
+
#
|
118
|
+
# Declares some default items to use if no custom items are provided.
|
119
|
+
#
|
120
|
+
def star_items
|
121
|
+
(1..@max).map do |rating|
|
122
|
+
input_attrs = {
|
123
|
+
loco_parent: component_ref,
|
124
|
+
css: ["where:mask where:mask-star", @inputs_css].compact.join(" "),
|
125
|
+
html: {
|
126
|
+
name: @name,
|
127
|
+
value: rating,
|
128
|
+
checked: @value == rating,
|
129
|
+
required: @required && rating == 1,
|
130
|
+
disabled: @disabled,
|
131
|
+
"aria-label": "#{rating} star",
|
132
|
+
**@inputs_html
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
RatingItemComponent.new(**input_attrs)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
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
|
+
= render_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
|
+
= render_component
|