fluxbit_view_components 0.2.0 → 0.4.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 +10 -0
- data/app/assets/javascripts/fluxbit_view_components/assigner_controller.js +49 -0
- data/app/assets/javascripts/fluxbit_view_components/auto_submit_controller.js +39 -0
- data/app/assets/javascripts/fluxbit_view_components/drawer_controller.js +135 -0
- data/app/assets/javascripts/fluxbit_view_components/index.js +56 -0
- data/app/assets/javascripts/fluxbit_view_components/method_link_controller.js +143 -0
- data/app/assets/javascripts/fluxbit_view_components/modal_controller.js +118 -0
- data/app/assets/javascripts/fluxbit_view_components/password_controller.js +170 -0
- data/app/assets/javascripts/fluxbit_view_components/progress_controller.js +374 -0
- data/app/assets/javascripts/fluxbit_view_components/row_click_controller.js +32 -0
- data/app/assets/javascripts/fluxbit_view_components/select_all_controller.js +122 -0
- data/app/assets/javascripts/fluxbit_view_components/spinner_percent_controller.js +174 -0
- data/app/assets/javascripts/fluxbit_view_components/theme_button_controller.js +90 -0
- data/app/assets/javascripts/fluxbit_view_components.js +1175 -0
- data/app/components/fluxbit/accordion_component.rb +125 -0
- data/app/components/fluxbit/alert_component.rb +8 -8
- data/app/components/fluxbit/avatar_component.rb +11 -12
- data/app/components/fluxbit/avatar_group_component.rb +1 -1
- data/app/components/fluxbit/badge_component.rb +8 -7
- data/app/components/fluxbit/banner_component.rb +139 -0
- data/app/components/fluxbit/bottom_navigation_component.rb +437 -0
- data/app/components/fluxbit/breadcrumb_component.rb +66 -0
- data/app/components/fluxbit/button_component.rb +39 -11
- data/app/components/fluxbit/button_group_component.rb +1 -1
- data/app/components/fluxbit/card_component.rb +26 -23
- data/app/components/fluxbit/carousel_component.rb +154 -0
- data/app/components/fluxbit/component.rb +24 -3
- data/app/components/fluxbit/drawer_component.html.erb +30 -0
- data/app/components/fluxbit/drawer_component.rb +125 -0
- data/app/components/fluxbit/dropdown_component.rb +41 -0
- data/app/components/fluxbit/dropdown_item_component.rb +68 -0
- data/app/components/fluxbit/flex_component.rb +1 -1
- data/app/components/fluxbit/form/check_box_component.rb +56 -0
- data/app/components/fluxbit/form/component.rb +27 -26
- data/app/components/fluxbit/form/dropzone_component.html.erb +39 -0
- data/app/components/fluxbit/form/dropzone_component.rb +39 -0
- data/app/components/fluxbit/form/field_component.rb +28 -0
- data/app/components/fluxbit/form/form_builder_component.rb +1 -1
- data/app/components/fluxbit/form/{helper_text_component.rb → help_text_component.rb} +9 -4
- data/app/components/fluxbit/form/label_component.rb +40 -30
- data/app/components/fluxbit/form/password_component.rb +247 -0
- data/app/components/fluxbit/form/radio_group_button_component.rb +126 -0
- data/app/components/fluxbit/form/range_component.rb +52 -0
- data/app/components/fluxbit/form/select_component.rb +185 -0
- data/app/components/fluxbit/form/text_field_component.rb +185 -0
- data/app/components/fluxbit/form/toggle_component.html.erb +23 -0
- data/app/components/fluxbit/form/toggle_component.rb +81 -0
- data/app/components/fluxbit/form/upload_image_component.html.erb +50 -0
- data/app/components/fluxbit/form/upload_image_component.rb +61 -0
- data/app/components/fluxbit/gravatar_component.rb +7 -0
- data/app/components/fluxbit/icon_helpers.rb +167 -0
- data/app/components/fluxbit/link_component.rb +42 -0
- data/app/components/fluxbit/modal_component.rb +28 -31
- data/app/components/fluxbit/pagination_component.rb +206 -0
- data/app/components/fluxbit/popover_component.rb +14 -14
- data/app/components/fluxbit/progress_component.rb +196 -0
- data/app/components/fluxbit/skeleton_component.rb +237 -0
- data/app/components/fluxbit/speed_dial_action_component.html.erb +30 -0
- data/app/components/fluxbit/speed_dial_action_component.rb +59 -0
- data/app/components/fluxbit/speed_dial_component.html.erb +33 -0
- data/app/components/fluxbit/speed_dial_component.rb +73 -0
- data/app/components/fluxbit/spinner_component.rb +71 -0
- data/app/components/fluxbit/spinner_percent_component.rb +174 -0
- data/app/components/fluxbit/stepper_component.rb +223 -0
- data/app/components/fluxbit/tab_component.rb +44 -25
- data/app/components/fluxbit/table_component.rb +186 -0
- data/app/components/fluxbit/table_group_component.rb +28 -0
- data/app/components/fluxbit/theme_button_component.rb +64 -0
- data/app/components/fluxbit/timeline_component.rb +63 -0
- data/app/components/fluxbit/timeline_item_component.html.erb +64 -0
- data/app/components/fluxbit/timeline_item_component.rb +78 -0
- data/app/components/fluxbit/tooltip_component.rb +2 -2
- data/app/helpers/fluxbit/components_helper.rb +93 -51
- data/app/helpers/fluxbit/form_builder.rb +136 -0
- data/app/helpers/fluxbit/view_helper.rb +71 -0
- data/config/locales/en.yml +37 -4
- data/config/locales/pt-BR.yml +36 -0
- data/lib/fluxbit/config/accordion_component.rb +73 -0
- data/lib/fluxbit/config/avatar_component.rb +11 -11
- data/lib/fluxbit/config/badge_component.rb +14 -11
- data/lib/fluxbit/config/banner_component.rb +60 -0
- data/lib/fluxbit/config/bottom_navigation_component.rb +74 -0
- data/lib/fluxbit/config/breadcrumb_component.rb +24 -0
- data/lib/fluxbit/config/button_component.rb +6 -4
- data/lib/fluxbit/config/card_component.rb +23 -12
- data/lib/fluxbit/config/carousel_component.rb +33 -0
- data/lib/fluxbit/config/drawer_component.rb +48 -0
- data/lib/fluxbit/config/dropdown_component.rb +29 -0
- data/lib/fluxbit/config/form/check_box_component.rb +19 -0
- data/lib/fluxbit/config/form/dropzone_component.rb +20 -0
- data/lib/fluxbit/config/form/{helper_text_component.rb → help_text_component.rb} +2 -2
- data/lib/fluxbit/config/form/label_component.rb +31 -0
- data/lib/fluxbit/config/form/password_component.rb +19 -0
- data/lib/fluxbit/config/form/radio_group_button_component.rb +24 -0
- data/lib/fluxbit/config/form/range_component.rb +15 -0
- data/lib/fluxbit/config/form/text_field_component.rb +76 -0
- data/lib/fluxbit/config/form/toggle_component.rb +79 -0
- data/lib/fluxbit/config/link_component.rb +24 -0
- data/lib/fluxbit/config/modal_component.rb +1 -1
- data/lib/fluxbit/config/pagination_component.rb +31 -0
- data/lib/fluxbit/config/popover_component.rb +1 -1
- data/lib/fluxbit/config/progress_component.rb +63 -0
- data/lib/fluxbit/config/skeleton_component.rb +82 -0
- data/lib/fluxbit/config/speed_dial_component.rb +50 -0
- data/lib/fluxbit/config/spinner_component.rb +30 -0
- data/lib/fluxbit/config/spinner_percent_component.rb +61 -0
- data/lib/fluxbit/config/stepper_component.rb +299 -0
- data/lib/fluxbit/config/tab_component.rb +6 -0
- data/lib/fluxbit/config/table_component.rb +75 -0
- data/lib/fluxbit/config/theme_button_component.rb +19 -0
- data/lib/fluxbit/config/timeline_component.rb +77 -0
- data/lib/fluxbit/view_components/engine.rb +11 -3
- data/lib/fluxbit/view_components/version.rb +1 -1
- data/lib/fluxbit/view_components.rb +27 -1
- data/lib/generators/fluxbit/devise_views_generator.rb +116 -0
- data/lib/generators/fluxbit/pagy_generator.rb +39 -0
- data/lib/generators/fluxbit/scaffold_generator.rb +165 -0
- data/lib/generators/fluxbit/templates/_alert.html.erb.tt +1 -0
- data/lib/generators/fluxbit/templates/_flash.html.erb.tt +15 -0
- data/lib/generators/fluxbit/templates/_form.html.erb.tt +38 -0
- data/lib/generators/fluxbit/templates/_metadata.html.erb.tt +44 -0
- data/lib/generators/fluxbit/templates/controller.rb.tt +406 -0
- data/lib/generators/fluxbit/templates/create.turbo_stream.erb.tt +7 -0
- data/lib/generators/fluxbit/templates/destroy.turbo_stream.erb.tt +3 -0
- data/lib/generators/fluxbit/templates/destroy_all.turbo_stream.erb.tt +9 -0
- data/lib/generators/fluxbit/templates/devise_views/confirmations/new.html.erb +11 -0
- data/lib/generators/fluxbit/templates/devise_views/layouts/devise.html.erb +64 -0
- data/lib/generators/fluxbit/templates/devise_views/mailer/confirmation_instructions.html.erb +5 -0
- data/lib/generators/fluxbit/templates/devise_views/mailer/email_changed.html.erb +7 -0
- data/lib/generators/fluxbit/templates/devise_views/mailer/password_changed.html.erb +3 -0
- data/lib/generators/fluxbit/templates/devise_views/mailer/reset_password_instructions.html.erb +8 -0
- data/lib/generators/fluxbit/templates/devise_views/mailer/unlock_instructions.html.erb +7 -0
- data/lib/generators/fluxbit/templates/devise_views/passwords/edit.html.erb +29 -0
- data/lib/generators/fluxbit/templates/devise_views/passwords/new.html.erb +11 -0
- data/lib/generators/fluxbit/templates/devise_views/registrations/edit.html.erb +43 -0
- data/lib/generators/fluxbit/templates/devise_views/registrations/new.html.erb +34 -0
- data/lib/generators/fluxbit/templates/devise_views/sessions/new.html.erb +15 -0
- data/lib/generators/fluxbit/templates/devise_views/shared/_error_messages.html.erb +14 -0
- data/lib/generators/fluxbit/templates/devise_views/shared/_links.html.erb +25 -0
- data/lib/generators/fluxbit/templates/devise_views/unlocks/new.html.erb +11 -0
- data/lib/generators/fluxbit/templates/edit.html.erb.tt +47 -0
- data/lib/generators/fluxbit/templates/fluxbit_pagy.css +27 -0
- data/lib/generators/fluxbit/templates/i18n.en.yml.tt +121 -0
- data/lib/generators/fluxbit/templates/i18n.pt-BR.yml.tt +121 -0
- data/lib/generators/fluxbit/templates/index.html.erb.tt +254 -0
- data/lib/generators/fluxbit/templates/index.json.jbuilder.tt +33 -0
- data/lib/generators/fluxbit/templates/new.html.erb.tt +47 -0
- data/lib/generators/fluxbit/templates/partial.html.erb.tt +61 -0
- data/lib/generators/fluxbit/templates/policy.rb.tt +36 -0
- data/lib/generators/fluxbit/templates/send_alert_via_drawer.erb.tt +10 -0
- data/lib/generators/fluxbit/templates/show.html.erb.tt +44 -0
- data/lib/generators/fluxbit/templates/show.json.jbuilder.tt +6 -0
- data/lib/generators/fluxbit/templates/update.turbo_stream.erb.tt +10 -0
- data/lib/generators/fluxbit/templates/update_all.turbo_stream.erb.tt +20 -0
- data/lib/install/install.rb +61 -3
- metadata +127 -35
- data/LICENSE.txt +0 -20
- data/app/components/fluxbit/form/checkbox_input_component.rb +0 -61
- data/app/components/fluxbit/form/datepicker_component.rb +0 -7
- data/app/components/fluxbit/form/radio_input_component.rb +0 -21
- data/app/components/fluxbit/form/range_input_component.rb +0 -51
- data/app/components/fluxbit/form/select_free_input_component.rb +0 -77
- data/app/components/fluxbit/form/select_input_component.rb +0 -21
- data/app/components/fluxbit/form/spacer_input_component.rb +0 -12
- data/app/components/fluxbit/form/text_input_component.rb +0 -225
- data/app/components/fluxbit/form/textarea_input_component.rb +0 -57
- data/app/components/fluxbit/form/toggle_input_component.rb +0 -166
- data/app/components/fluxbit/form/upload_image_input_component.html.erb +0 -48
- data/app/components/fluxbit/form/upload_image_input_component.rb +0 -61
- data/app/components/fluxbit/form/upload_input_component.html.erb +0 -12
- data/app/components/fluxbit/form/upload_input_component.rb +0 -47
- data/app/helpers/fluxbit/classes_helper.rb +0 -9
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# The `Fluxbit::Form::RadioGroupButtonComponent` is a component for rendering radio buttons
|
|
5
|
+
# styled as a button group. It provides the visual appearance of grouped buttons while
|
|
6
|
+
# maintaining radio button behavior (only one option can be selected at a time).
|
|
7
|
+
#
|
|
8
|
+
# This component is useful for creating segmented controls, view toggles, or any interface
|
|
9
|
+
# where users need to select one option from a group with a button-like appearance.
|
|
10
|
+
class Fluxbit::Form::RadioGroupButtonComponent < Fluxbit::Form::FieldComponent
|
|
11
|
+
include Fluxbit::Config::Form::RadioGroupButtonComponent
|
|
12
|
+
|
|
13
|
+
renders_many :radio_options, lambda { |**props, &block|
|
|
14
|
+
@options_group << ComponentObj.new(props, view_context.capture(&block))
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
##
|
|
18
|
+
# Initializes the radio group button component with the given properties.
|
|
19
|
+
#
|
|
20
|
+
# @param [Hash] props The properties to customize the radio group button.
|
|
21
|
+
# @option props [String] :name (nil) The name attribute for the radio button group (required for proper radio functionality).
|
|
22
|
+
# @option props [Symbol, String] :color (:default) The color style of the buttons.
|
|
23
|
+
# @option props [Symbol, String] :size (1) The size of the buttons (e.g., `0` to `4`).
|
|
24
|
+
# @option props [Boolean] :pill (false) Determines if the buttons have pill-shaped edges.
|
|
25
|
+
# @option props [Hash] **props Remaining options declared as HTML attributes, applied to the group container.
|
|
26
|
+
#
|
|
27
|
+
# @return [Fluxbit::Form::RadioGroupButtonComponent]
|
|
28
|
+
def initialize(**props)
|
|
29
|
+
super
|
|
30
|
+
@props = props
|
|
31
|
+
@name = @props.delete(:name) || "radio_group_#{fx_id}"
|
|
32
|
+
@color = options (@props.delete(:color) || "").to_sym, collection: button_styles[:colors].keys, default: @@color
|
|
33
|
+
@size = @props.delete(:size) || @@size
|
|
34
|
+
@pill = options @props.delete(:pill), default: false
|
|
35
|
+
@outline = @color.to_s.end_with?("_outline")
|
|
36
|
+
@options_group = []
|
|
37
|
+
|
|
38
|
+
add class: Fluxbit::Config::Form::RadioGroupButtonComponent.styles[:group], to: @props, first_element: true
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def call
|
|
42
|
+
radio_options
|
|
43
|
+
tag.div(**@props) do
|
|
44
|
+
@options_group.each_with_index do |option, index|
|
|
45
|
+
concat render_radio_button(option, index)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def render_radio_button(option, index)
|
|
53
|
+
option_props = option.props || {}
|
|
54
|
+
option_content = option.content
|
|
55
|
+
option_value = option_props.delete(:value) || index
|
|
56
|
+
option_checked = option_props.delete(:checked) || false
|
|
57
|
+
option_disabled = option_props.delete(:disabled) || false
|
|
58
|
+
|
|
59
|
+
radio_id = "#{@name}_#{option_value}_#{fx_id}"
|
|
60
|
+
|
|
61
|
+
# Input element
|
|
62
|
+
input_html = {
|
|
63
|
+
type: "radio",
|
|
64
|
+
id: radio_id,
|
|
65
|
+
name: @name,
|
|
66
|
+
value: option_value,
|
|
67
|
+
class: "#{Fluxbit::Config::Form::RadioGroupButtonComponent.styles[:input]} peer"
|
|
68
|
+
}
|
|
69
|
+
input_html[:checked] = true if option_checked
|
|
70
|
+
input_html[:disabled] = true if option_disabled
|
|
71
|
+
|
|
72
|
+
# Label element (styled as button)
|
|
73
|
+
label_html = option_props.dup
|
|
74
|
+
label_html[:for] = radio_id
|
|
75
|
+
|
|
76
|
+
add class: Fluxbit::Config::Form::RadioGroupButtonComponent.styles[:label][:base], to: label_html, first_element: true
|
|
77
|
+
add class: button_color_classes, to: label_html, first_element: true
|
|
78
|
+
add class: button_size_classes, to: label_html, first_element: true
|
|
79
|
+
add class: button_pill_classes, to: label_html, first_element: true
|
|
80
|
+
add class: button_outline_classes, to: label_html, first_element: true
|
|
81
|
+
|
|
82
|
+
# Position classes
|
|
83
|
+
add class: Fluxbit::Config::Form::RadioGroupButtonComponent.styles[:label][:position][:start], to: label_html if index == 0
|
|
84
|
+
add class: Fluxbit::Config::Form::RadioGroupButtonComponent.styles[:label][:position][:end], to: label_html if index == @options_group.size - 1
|
|
85
|
+
add class: Fluxbit::Config::Form::RadioGroupButtonComponent.styles[:label][:position][:middle], to: label_html if index > 0 && index < @options_group.size - 1
|
|
86
|
+
|
|
87
|
+
# Selected state - use peer-checked for CSS-only interaction
|
|
88
|
+
# The peer modifier allows the label to change when the radio input is checked
|
|
89
|
+
add class: "peer-checked:brightness-90 dark:peer-checked:brightness-75", to: label_html
|
|
90
|
+
|
|
91
|
+
# Disabled state
|
|
92
|
+
if option_disabled
|
|
93
|
+
add class: Fluxbit::Config::ButtonComponent.styles[:disabled], to: label_html, first_element: true
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
tag.div(class: "relative") do
|
|
97
|
+
concat tag.input(**input_html)
|
|
98
|
+
concat tag.label(option_content, **label_html)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def button_styles
|
|
103
|
+
Fluxbit::Config::ButtonComponent.styles
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def button_color_classes
|
|
107
|
+
@color.in?(button_styles[:colors].keys) ? button_styles[:colors][@color] : button_styles[:colors][:default]
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def button_size_classes
|
|
111
|
+
button_styles[:size][@size.to_i]
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def button_pill_classes
|
|
115
|
+
return "" if @outline
|
|
116
|
+
button_styles[:pill][@pill ? :on : :off]
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def button_outline_classes
|
|
120
|
+
if @outline
|
|
121
|
+
"#{button_styles[:outline][:on]} #{button_styles[:outline][:pill][@pill ? :on : :off]}"
|
|
122
|
+
else
|
|
123
|
+
button_styles[:outline][:off]
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# The `Fluxbit::Form::RangeComponent` renders a styled range slider for selecting numeric values within a range.
|
|
4
|
+
# It supports vertical and horizontal orientation, sizing options, helper text, labels, and full compatibility with Rails form builders.
|
|
5
|
+
# Custom classes and HTML attributes can be passed for further styling and control.
|
|
6
|
+
#
|
|
7
|
+
# @example Basic usage
|
|
8
|
+
# = render Fluxbit::Form::RangeComponent.new(name: :volume, label: "Volume")
|
|
9
|
+
#
|
|
10
|
+
# @see docs/03_Forms/Range.md For detailed documentation and examples.
|
|
11
|
+
class Fluxbit::Form::RangeComponent < Fluxbit::Form::FieldComponent
|
|
12
|
+
include Fluxbit::Config::Form::RangeComponent
|
|
13
|
+
|
|
14
|
+
# Initializes the range component with the given properties.
|
|
15
|
+
#
|
|
16
|
+
# @param name [String] Name of the field (required unless using form builder)
|
|
17
|
+
# @param label [String] Label for the input (optional)
|
|
18
|
+
# @param value [Numeric] Value for the range input (optional)
|
|
19
|
+
# @param min [Numeric] Minimum value for the range slider (optional)
|
|
20
|
+
# @param max [Numeric] Maximum value for the range slider (optional)
|
|
21
|
+
# @param step [Numeric] Step value for the slider (optional)
|
|
22
|
+
# @param vertical [Boolean] Renders the slider vertically if true (default: false)
|
|
23
|
+
# @param sizing [Integer] Size index for slider height/thickness (default: config default)
|
|
24
|
+
# @param help_text [String] Helper or error text below the field
|
|
25
|
+
# @param class [String] Additional CSS classes for the input element
|
|
26
|
+
# @param ... any other HTML attribute supported by the <input type="range"> tag
|
|
27
|
+
def initialize(**props)
|
|
28
|
+
super(**props)
|
|
29
|
+
@vertical = options(@props.delete(:vertical), collection: [ true, false ], default: @@vertical)
|
|
30
|
+
@sizing = @props[:sizing].to_i || @@sizing
|
|
31
|
+
@sizing = (styles[:sizes].count - 1) if @sizing > (styles[:sizes].count - 1)
|
|
32
|
+
@props[:type] = "range"
|
|
33
|
+
@props[:style] = @props[:style] || "" + ";transform: rotate(270deg);" if @vertical
|
|
34
|
+
|
|
35
|
+
add(class: styles[:sizes][@sizing], to: @props, first_element: true)
|
|
36
|
+
add(class: styles[:base], to: @props, first_element: true)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def range
|
|
40
|
+
if @form.nil?
|
|
41
|
+
text_field_tag @name, @value, @props
|
|
42
|
+
else
|
|
43
|
+
@form.text_field(@attribute, **@props)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def call
|
|
48
|
+
content_tag :div, **@wrapper_html do
|
|
49
|
+
safe_join [ label, range, help_text ]
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# The `Fluxbit::Form::SelectComponent` is a styled dropdown/select field for forms.
|
|
4
|
+
# It supports standard, grouped, and time zone options, integrates with Rails form builders,
|
|
5
|
+
# and provides flexible props for prompt, disabled/selected options, helper text, and more.
|
|
6
|
+
#
|
|
7
|
+
# @example Basic usage
|
|
8
|
+
# = render Fluxbit::Form::SelectComponent.new(name: :role, options: ["Admin", "User", "Guest"], label: "User Role")
|
|
9
|
+
#
|
|
10
|
+
# @see docs/03_Forms/Select.md For detailed documentation and examples.
|
|
11
|
+
class Fluxbit::Form::SelectComponent < Fluxbit::Form::TextFieldComponent
|
|
12
|
+
# Initializes the select component with the given properties.
|
|
13
|
+
#
|
|
14
|
+
# @param name [String] Name of the field (required unless using form builder)
|
|
15
|
+
# @param label [String, false] Label text for the select field (optional, auto-generated from attribute if using form builder)
|
|
16
|
+
# @param help_text [String, Array, false] Help text displayed below the field (optional, supports i18n)
|
|
17
|
+
# @param helper_popover [String, false] Content for an info popover next to the label (optional, supports i18n)
|
|
18
|
+
# @param helper_popover_placement [String] Placement of the popover: "top", "right", "bottom", "left" (default: "right")
|
|
19
|
+
# @param value [String] Value for the field (optional)
|
|
20
|
+
# @param grouped [Boolean] Enables grouped select options (default: false)
|
|
21
|
+
# @param time_zone [Boolean] Uses Rails time zone select options (default: false)
|
|
22
|
+
# @param select_options [Hash] Options for select tag (prompt, selected, disabled, etc)
|
|
23
|
+
# @param choices [Array] List of choices for options (alternative to options)
|
|
24
|
+
# @param options [Array, Hash, String] List or hash of options, or pre-formatted HTML from options_for_select
|
|
25
|
+
# @param prompt [String, Boolean, false] Prompt text, true to use default, or false to disable (optional, defaults to I18n if object/attribute present)
|
|
26
|
+
# @param include_blank [String, Boolean] Include blank option (optional)
|
|
27
|
+
# @param selected [Object] Pre-selected value (optional)
|
|
28
|
+
# @param disabled [Array, Object] Disabled options (optional)
|
|
29
|
+
# @param color [Symbol] Color state: :default, :success, :danger, :warning, :info (optional)
|
|
30
|
+
# @param sizing [Integer] Field size (0 to 2, default: 1)
|
|
31
|
+
# @param class [String] Additional CSS classes for the select element
|
|
32
|
+
# @param ... any other HTML attribute supported by <select>
|
|
33
|
+
def initialize(**props)
|
|
34
|
+
super(**props)
|
|
35
|
+
@grouped = @props.delete(:grouped) || false
|
|
36
|
+
@time_zone = @props.delete(:time_zone) || false
|
|
37
|
+
@select_options = @props.delete(:select_options) || {}
|
|
38
|
+
@choices = @props.delete(:choices) || nil
|
|
39
|
+
@options = @props.delete(:options) || {}
|
|
40
|
+
|
|
41
|
+
# Extract select-specific options
|
|
42
|
+
prompt_value = @select_options.delete(:prompt) || @props.delete(:prompt)
|
|
43
|
+
@include_blank = @select_options.delete(:include_blank) || @props.delete(:include_blank)
|
|
44
|
+
@selected = @select_options.delete(:selected) || @props.delete(:selected)
|
|
45
|
+
@disabled_options = @select_options.delete(:disabled) || @props.delete(:disabled)
|
|
46
|
+
|
|
47
|
+
@options = ::ActiveSupport::TimeZone.all if @time_zone
|
|
48
|
+
|
|
49
|
+
# Define prompt with I18n support
|
|
50
|
+
define_prompt(prompt_value)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def input
|
|
54
|
+
if @form.present? && @attribute.present?
|
|
55
|
+
# form.select(attribute, choices, options = {}, html_options = {})
|
|
56
|
+
# For form builder with time zones, use the specialized helper
|
|
57
|
+
if @time_zone
|
|
58
|
+
@form.time_zone_select(@attribute, nil, build_select_options_hash, @props)
|
|
59
|
+
else
|
|
60
|
+
# form.select can accept raw choices OR pre-formatted option tags
|
|
61
|
+
# We use pre-formatted tags for consistency with grouped selects
|
|
62
|
+
@form.select(
|
|
63
|
+
@attribute,
|
|
64
|
+
build_options_for_select,
|
|
65
|
+
build_select_options_hash,
|
|
66
|
+
@props
|
|
67
|
+
)
|
|
68
|
+
end
|
|
69
|
+
else
|
|
70
|
+
# select_tag(name, option_tags = nil, options = {})
|
|
71
|
+
# option_tags should be pre-formatted HTML
|
|
72
|
+
select_tag(
|
|
73
|
+
@name,
|
|
74
|
+
build_options_for_select,
|
|
75
|
+
@props
|
|
76
|
+
)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Build options hash for form.select (prompt, include_blank, etc.)
|
|
81
|
+
# Note: Don't include selected/disabled if options are pre-formatted HTML
|
|
82
|
+
def build_select_options_hash
|
|
83
|
+
options_hash = @select_options.dup
|
|
84
|
+
options_hash[:prompt] = @prompt if @prompt
|
|
85
|
+
options_hash[:include_blank] = @include_blank if @include_blank
|
|
86
|
+
|
|
87
|
+
# Only add selected/disabled if we're building options from raw data
|
|
88
|
+
unless options_are_preformatted?
|
|
89
|
+
options_hash[:selected] = @selected if @selected
|
|
90
|
+
options_hash[:disabled] = @disabled_options if @disabled_options
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
options_hash
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Build pre-formatted option tags for select_tag and form.select
|
|
97
|
+
def build_options_for_select
|
|
98
|
+
# If options are already HTML (from options_for_select/grouped_options_for_select), use as-is
|
|
99
|
+
if options_are_preformatted?
|
|
100
|
+
html = @options.dup
|
|
101
|
+
# Add prompt if needed and not already in the HTML (only for select_tag)
|
|
102
|
+
html = add_prompt_to_html(html) if @prompt && !html.include?(@prompt.to_s) && !using_form_builder?
|
|
103
|
+
return html
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Otherwise, build the HTML from raw data
|
|
107
|
+
html = if @grouped
|
|
108
|
+
grouped_options_for_select(
|
|
109
|
+
@options,
|
|
110
|
+
@selected,
|
|
111
|
+
disabled: @disabled_options,
|
|
112
|
+
divider: @divider
|
|
113
|
+
)
|
|
114
|
+
elsif @time_zone
|
|
115
|
+
time_zone_options_for_select(@selected)
|
|
116
|
+
else
|
|
117
|
+
options_for_select(@options, selected: @selected, disabled: @disabled_options)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Add prompt option at the beginning if specified
|
|
121
|
+
# Only add it manually for select_tag (form.select handles it via options hash)
|
|
122
|
+
html = add_prompt_to_html(html) if @prompt && !using_form_builder?
|
|
123
|
+
html
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
private
|
|
127
|
+
|
|
128
|
+
# Check if we're using a form builder
|
|
129
|
+
def using_form_builder?
|
|
130
|
+
@form.present? && @attribute.present?
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def define_prompt(prompt)
|
|
134
|
+
# If prompt is explicitly false, don't set it
|
|
135
|
+
return if prompt.is_a?(FalseClass)
|
|
136
|
+
|
|
137
|
+
# If prompt is explicitly provided (string or true), use it
|
|
138
|
+
if prompt.present?
|
|
139
|
+
@prompt = prompt
|
|
140
|
+
return
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# If no prompt provided and we have an object and attribute, try I18n lookup
|
|
144
|
+
if prompt.nil? && @object.present? && @attribute.present?
|
|
145
|
+
i18n_prompt = I18n.t(
|
|
146
|
+
@attribute,
|
|
147
|
+
scope: [ @object.class.name.pluralize.underscore.to_sym, :prompts ],
|
|
148
|
+
default: nil
|
|
149
|
+
)
|
|
150
|
+
@prompt = i18n_prompt if i18n_prompt.present?
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Check if options are already pre-formatted HTML
|
|
155
|
+
# Pre-formatted options are strings containing HTML tags
|
|
156
|
+
def options_are_preformatted?
|
|
157
|
+
@options.is_a?(String) && @options.include?("<option")
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Add prompt option to the beginning of the HTML options
|
|
161
|
+
def add_prompt_to_html(html)
|
|
162
|
+
prompt_text = @prompt.is_a?(String) ? @prompt : "Please select"
|
|
163
|
+
prompt_option = "<option value=\"\">#{ERB::Util.html_escape(prompt_text)}</option>".html_safe
|
|
164
|
+
prompt_option + html
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def grouped_selected_option
|
|
168
|
+
@options.each do |group|
|
|
169
|
+
group_to_traverse = @divider ? group[1] : group
|
|
170
|
+
if group_to_traverse.is_a?(String)
|
|
171
|
+
return group_to_traverse if group_to_traverse == @selected.to_s
|
|
172
|
+
|
|
173
|
+
next
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
group_to_traverse.each do |item|
|
|
177
|
+
if item.is_a?(Array) && item[1] == @selected.to_s
|
|
178
|
+
return item[0]
|
|
179
|
+
elsif item.is_a?(String) && item == @selected.to_s
|
|
180
|
+
return item
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# The `Fluxbit::Form::TextFieldComponent` is a form input component that extends `Fluxbit::Form::FieldComponent`.
|
|
4
|
+
# It provides a styled text input (or textarea) with support for various HTML input types, optional icons or add-on content,
|
|
5
|
+
# and color-coded validation states (e.g. default, success, error).
|
|
6
|
+
#
|
|
7
|
+
# @example Basic usage
|
|
8
|
+
# = render Fluxbit::Form::TextFieldComponent.new(name: :email)
|
|
9
|
+
#
|
|
10
|
+
# @see docs/03_Forms/TextField.md For detailed documentation and examples.
|
|
11
|
+
class Fluxbit::Form::TextFieldComponent < Fluxbit::Form::FieldComponent
|
|
12
|
+
TYPE_DEFAULT = :text
|
|
13
|
+
TYPE_OPTIONS = %i[text textarea text_area color number email password search tel url date datetime_local month time week currency]
|
|
14
|
+
include Fluxbit::Config::Form::TextFieldComponent
|
|
15
|
+
|
|
16
|
+
# Initializes the text field component with the given properties.
|
|
17
|
+
#
|
|
18
|
+
# @param form [ActionView::Helpers::FormBuilder] The form builder (optional, for Rails forms)
|
|
19
|
+
# @param attribute [Symbol] The model attribute to be used in the form (required if using form builder)
|
|
20
|
+
# @param id [String] The id of the input element (optional)
|
|
21
|
+
# @param label [String] The label for the input field (optional)
|
|
22
|
+
# @param help_text [String] Additional help text for the input field (optional)
|
|
23
|
+
# @param helper_popover [String] Content for a popover helper (optional)
|
|
24
|
+
# @param helper_popover_placement [String] Placement of the popover (default: "right")
|
|
25
|
+
# @param name [String] Name of the field (required, unless using form builder)
|
|
26
|
+
# @param value [String] Value for the field (optional)
|
|
27
|
+
# @param placeholder [String] Placeholder text for the input field (optional, defaults to I18n if object/attribute present, pass false to disable)
|
|
28
|
+
# @param type [Symbol] Input type (`:text`, `:email`, etc)
|
|
29
|
+
# @param icon [Symbol] Left icon (optional)
|
|
30
|
+
# @param right_icon [Symbol] Right icon (optional)
|
|
31
|
+
# @param addon [String] Add-on text or icon before the input (optional)
|
|
32
|
+
# @param addon_html [Hash] Props for the Add-on (optional)
|
|
33
|
+
# @param icon_html [Hash] Props for the left icon (optional)
|
|
34
|
+
# @param right_icon_html [Hash] Props for the right icon (optional)
|
|
35
|
+
# @param div_html [Hash] Props for the whole div (optional)
|
|
36
|
+
# @param multiline [Boolean] Renders a textarea if true
|
|
37
|
+
# @param color [Symbol] Field color (`:default`, `:success`, `:danger`, etc)
|
|
38
|
+
# @param sizing [Integer] Input size
|
|
39
|
+
# @param shadow [Boolean] Adds drop shadow if true
|
|
40
|
+
# @param disabled [Boolean] Disables the input if true
|
|
41
|
+
# @param readonly [Boolean] Makes the input readonly if true
|
|
42
|
+
# @param ... any other HTML attribute supported by input/textarea
|
|
43
|
+
def initialize(**props)
|
|
44
|
+
super(**props)
|
|
45
|
+
@color = valid_color(@props.delete(:color))
|
|
46
|
+
@type = options(@props.delete(:type), collection: TYPE_OPTIONS, default: TYPE_DEFAULT)
|
|
47
|
+
@icon = @props.delete(:icon)
|
|
48
|
+
@multiline = options(@props.delete(:multiline), default: false)
|
|
49
|
+
@shadow = @props.delete(:shadow)
|
|
50
|
+
@addon = @props.delete(:addon)
|
|
51
|
+
@right_icon = @props.delete(:right_icon)
|
|
52
|
+
@addon_html = @props.delete(:addon_html) || {}
|
|
53
|
+
@div_html = @props.delete(:div_html) || {}
|
|
54
|
+
@icon_html = @props.delete(:icon_html) || {}
|
|
55
|
+
@right_icon_html = @props.delete(:right_icon_html) || {}
|
|
56
|
+
@sizing = sizing_with_addon @props.delete(:sizing)
|
|
57
|
+
@props[:type] = @type
|
|
58
|
+
|
|
59
|
+
define_placeholder(@props.delete(:placeholder))
|
|
60
|
+
declare_classes
|
|
61
|
+
@props[:class] = remove_class(@props.delete(:remove_class) || "", @props[:class])
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def call
|
|
65
|
+
content_tag :div, **@wrapper_html do
|
|
66
|
+
safe_join [ label, icon_container, help_text ]
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def define_placeholder(placeholder)
|
|
73
|
+
return if placeholder.is_a?(FalseClass)
|
|
74
|
+
|
|
75
|
+
if placeholder.nil? && @object.present? && @attribute.present?
|
|
76
|
+
placeholder = I18n.t(
|
|
77
|
+
@attribute,
|
|
78
|
+
scope: [ @object.class.name.pluralize.underscore.to_sym, :placeholders ],
|
|
79
|
+
default: nil
|
|
80
|
+
)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
@props[:placeholder] = placeholder if placeholder.present?
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def valid_color(color)
|
|
87
|
+
return color if styles[:bg].key?(color)
|
|
88
|
+
return :danger if errors.present?
|
|
89
|
+
|
|
90
|
+
@@color
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def sizing_with_addon(sizing)
|
|
94
|
+
sizing.to_i < styles[:sizes].count ? sizing.to_i : @@sizing
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def declare_classes
|
|
98
|
+
add to: @props,
|
|
99
|
+
first_element: true,
|
|
100
|
+
class: [
|
|
101
|
+
styles[:default],
|
|
102
|
+
(@props.key?(:readonly) || @props.key?(:disabled) ? styles[:text][@color] : nil),
|
|
103
|
+
styles[:ring][@color],
|
|
104
|
+
styles[:bg][@color],
|
|
105
|
+
styles[:placeholder][@color],
|
|
106
|
+
styles[:border][@color],
|
|
107
|
+
@addon ? styles[:sizing_md_addon] : styles[:sizes][@sizing],
|
|
108
|
+
(@shadow ? styles[:shadow] : nil),
|
|
109
|
+
(@right_icon ? styles[:right_icon] : nil),
|
|
110
|
+
(@icon ? styles[:icon] : nil)
|
|
111
|
+
].compact.join(" ")
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def icon(icon_v, tag: :div, props: nil)
|
|
115
|
+
return "" if icon_v.blank?
|
|
116
|
+
|
|
117
|
+
content_tag(
|
|
118
|
+
tag,
|
|
119
|
+
anyicon(
|
|
120
|
+
icon_v,
|
|
121
|
+
class: styles[:additional_icons][:class][@color]
|
|
122
|
+
),
|
|
123
|
+
**props
|
|
124
|
+
)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def create_icon
|
|
128
|
+
add class: styles[:additional_icons][:icon], to: @icon_html
|
|
129
|
+
add(class: "pointer-events-none", to: @icon_html) unless events?(@icon_html)
|
|
130
|
+
icon(@icon, props: @icon_html)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def create_addon
|
|
134
|
+
add class: styles[:additional_icons][:addon][@color], to: @addon_html
|
|
135
|
+
icon(@addon, tag: :span, props: @addon_html)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def create_right_icon
|
|
139
|
+
add class: styles[:additional_icons][:right_icon], to: @right_icon_html
|
|
140
|
+
add(class: "pointer-events-none", to: @right_icon_html) unless events?(@right_icon_html)
|
|
141
|
+
icon(@right_icon, props: @right_icon_html)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def events?(props)
|
|
145
|
+
props.keys.intersection(
|
|
146
|
+
%i[onclick onsubmit onchange onkeydown onkeyup onkeypress href]
|
|
147
|
+
).present?
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def input
|
|
151
|
+
input_type = case @type
|
|
152
|
+
when :text
|
|
153
|
+
@multiline ? "text_area" : "text_field"
|
|
154
|
+
when :tel then "telephone_field"
|
|
155
|
+
when :currency then "text_field"
|
|
156
|
+
when :textarea, :text_area then "text_area"
|
|
157
|
+
else
|
|
158
|
+
"#{@type}_field"
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
if @form.present? && @attribute.present?
|
|
162
|
+
@props[:value] = @value if @value.present?
|
|
163
|
+
@form.public_send(input_type, @attribute, @props)
|
|
164
|
+
else
|
|
165
|
+
public_send("#{input_type}_tag", @name, @value, @props)
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def icon_container_with_addon
|
|
170
|
+
add class: "flex", to: @div_html
|
|
171
|
+
content_tag :div, safe_join([ create_addon, create_right_icon, input ]), @div_html
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def icon_container_without_addon
|
|
175
|
+
add class: "relative w-full", to: @div_html
|
|
176
|
+
content_tag :div, safe_join([ create_icon, create_right_icon, input ]), @div_html
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def icon_container
|
|
180
|
+
return input if @icon.nil? && @right_icon.nil? && @addon.nil?
|
|
181
|
+
return icon_container_with_addon unless @addon.nil?
|
|
182
|
+
|
|
183
|
+
icon_container_without_addon
|
|
184
|
+
end
|
|
185
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<%= content_tag :div, **@wrapper_html do %>
|
|
2
|
+
<label class="<%= label_class %>">
|
|
3
|
+
<%= if @invert_label
|
|
4
|
+
label
|
|
5
|
+
else
|
|
6
|
+
@other_label || (other_label if other_label?)
|
|
7
|
+
end %>
|
|
8
|
+
|
|
9
|
+
<% if @form.present? && @attribute.present? %>
|
|
10
|
+
<%= @form.check_box(@attribute, **@props) %>
|
|
11
|
+
<% else %>
|
|
12
|
+
<%= check_box_tag(@name, **@props) %>
|
|
13
|
+
<% end %>
|
|
14
|
+
|
|
15
|
+
<span class="<%= toggle_class %>"></span>
|
|
16
|
+
<%= if @invert_label
|
|
17
|
+
@other_label || (other_label if other_label?)
|
|
18
|
+
else
|
|
19
|
+
label
|
|
20
|
+
end %>
|
|
21
|
+
</label>
|
|
22
|
+
<%= help_text %>
|
|
23
|
+
<% end %>
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
# The `Fluxbit::Form::ToggleComponent` renders a styled switch/toggle (on/off) input.
|
|
5
|
+
# It supports custom label placement, color and sizing options, helper text, and is fully compatible
|
|
6
|
+
# with Rails form builders. Additional options allow you to invert label order, customize colors
|
|
7
|
+
# for checked/unchecked/button states, and provide an extra label via a slot.
|
|
8
|
+
#
|
|
9
|
+
# @example Basic usage
|
|
10
|
+
# = render Fluxbit::Form::ToggleComponent.new(name: :enabled, label: "Enabled?")
|
|
11
|
+
#
|
|
12
|
+
# @see docs/03_Forms/Toggle.md For detailed documentation and examples.
|
|
13
|
+
class Fluxbit::Form::ToggleComponent < Fluxbit::Form::FieldComponent
|
|
14
|
+
include Fluxbit::Config::Form::ToggleComponent
|
|
15
|
+
|
|
16
|
+
renders_one :other_label, "Fluxbit::Form::LabelComponent"
|
|
17
|
+
|
|
18
|
+
# Initializes the toggle component with the given properties.
|
|
19
|
+
#
|
|
20
|
+
# @param form [ActionView::Helpers::FormBuilder] The form builder (optional, for Rails forms)
|
|
21
|
+
# @param attribute [Symbol] The model attribute to be used in the form (required if using form builder)
|
|
22
|
+
# @param id [String] The id of the input element (optional)
|
|
23
|
+
# @param label [String] The label for the input field (optional)
|
|
24
|
+
# @param help_text [String] Additional help text for the input field (optional)
|
|
25
|
+
# @param helper_popover [String] Content for a popover helper (optional)
|
|
26
|
+
# @param helper_popover_placement [String] Placement of the popover (default: "right")
|
|
27
|
+
# @param name [String] Name of the field (required unless using form builder)
|
|
28
|
+
# @param other_label [String] Additional label, rendered via slot (optional)
|
|
29
|
+
# @param sizing [Integer] Size index for the toggle (default: config)
|
|
30
|
+
# @param color [Symbol] Checked toggle color (:default, :success, :danger, :info, :warning, etc)
|
|
31
|
+
# @param unchecked_color [Symbol] Unchecked toggle color (see config)
|
|
32
|
+
# @param button_color [Symbol] Color for the toggle button
|
|
33
|
+
# @param invert_label [Boolean] If true, inverts label/toggle order (default: config)
|
|
34
|
+
# @param disabled [Boolean] Disables the toggle if true
|
|
35
|
+
# @param class [String] Additional CSS classes for the input element
|
|
36
|
+
# @param ... any other HTML attribute supported by <input type="checkbox">
|
|
37
|
+
def initialize(**props)
|
|
38
|
+
super(**props)
|
|
39
|
+
|
|
40
|
+
@other_label = props.delete(:other_label)
|
|
41
|
+
@sizing = @props.delete(:sizing) || @@sizing
|
|
42
|
+
@sizing = (styles[:toggle][:sizes].count - 1) if @sizing > (styles[:toggle][:sizes].count - 1)
|
|
43
|
+
@color = valid_color(@props.delete(:color))
|
|
44
|
+
@unchecked_color = options(
|
|
45
|
+
@props.delete(:unchecked_color),
|
|
46
|
+
collection: styles[:toggle][:unchecked].keys,
|
|
47
|
+
default: @@unchecked_color
|
|
48
|
+
)
|
|
49
|
+
@button_color = options(@props.delete(:button_color), collection: styles[:toggle][:button].keys, default: @@button_color)
|
|
50
|
+
@invert_label = options(@props.delete(:invert_label), collection: [ true, false ], default: @@invert_label)
|
|
51
|
+
|
|
52
|
+
add to: @props, first_element: true, class: styles[:input]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def valid_color(color)
|
|
56
|
+
return color if styles[:toggle][:checked].key?(color)
|
|
57
|
+
return :danger if errors.present?
|
|
58
|
+
|
|
59
|
+
@@color
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def label_class
|
|
63
|
+
styles[:label]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def input_class
|
|
67
|
+
styles[:input]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def toggle_class
|
|
71
|
+
[
|
|
72
|
+
(@invert_label || @other_label || other_label?) ? styles[:toggle][:invert_label] : nil,
|
|
73
|
+
styles[:toggle][:base],
|
|
74
|
+
styles[:toggle][:unchecked][@unchecked_color],
|
|
75
|
+
styles[:toggle][:checked][@color],
|
|
76
|
+
styles[:toggle][:button][@button_color],
|
|
77
|
+
styles[:toggle][:sizes][@sizing],
|
|
78
|
+
styles[:toggle][:active][(@props[:disabled] ? :off : :on)]
|
|
79
|
+
].compact.join(" ")
|
|
80
|
+
end
|
|
81
|
+
end
|