fluxbit_view_components 0.1.0 → 0.3.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 +7 -1
- data/app/components/fluxbit/form/check_box_component.rb +56 -0
- data/app/components/fluxbit/form/component.rb +20 -25
- 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 +26 -0
- data/app/components/fluxbit/form/form_builder_component.rb +5 -7
- data/app/components/fluxbit/form/{helper_text_component.rb → help_text_component.rb} +8 -3
- data/app/components/fluxbit/form/label_component.rb +32 -29
- data/app/components/fluxbit/form/range_component.rb +52 -0
- data/app/components/fluxbit/form/select_component.rb +88 -0
- data/app/components/fluxbit/form/text_field_component.rb +168 -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 +50 -0
- data/app/helpers/fluxbit/classes_helper.rb +0 -12
- data/app/helpers/fluxbit/components_helper.rb +23 -51
- data/app/helpers/fluxbit/form_builder.rb +87 -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} +1 -1
- data/lib/fluxbit/config/form/label_component.rb +30 -0
- data/lib/fluxbit/config/form/range_component.rb +15 -0
- data/lib/fluxbit/config/form/text_field_component.rb +76 -0
- data/{app/components/fluxbit/form/toggle_input_component.rb → lib/fluxbit/config/form/toggle_component.rb} +28 -115
- data/lib/fluxbit/templates/darkmode.js.template +7 -0
- data/lib/fluxbit/templates/tailwind.config.js.template +4 -0
- data/lib/fluxbit/view_components/version.rb +1 -3
- data/lib/fluxbit/view_components.rb +7 -1
- data/lib/install/install.rb +57 -47
- data/lib/tasks/fluxbit_view_components_tasks.rake +30 -10
- metadata +25 -25
- 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/upload_image_input_component.html.erb +0 -48
- data/app/components/fluxbit/form/upload_image_input_component.rb +0 -66
- data/app/components/fluxbit/form/upload_input_component.html.erb +0 -12
- data/app/components/fluxbit/form/upload_input_component.rb +0 -47
- data/lib/fluxbit/view_components/codemods/v3_slot_setters.rb +0 -222
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f5ca4fde5d32556cdbc0f25088912fa549531dea43e9e46557806c742a61a3c
|
4
|
+
data.tar.gz: 2feca2ea7274688b6d1e850aee6dc6d5638718718584e977514f0abf96cedd8e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85ef792f0b9ead019bf89459531723043c7b771fe7b6c8f016ba03697d2e80d93139a081e0f4250d46545eb97b31f159fcaa9ba2bd5592c27053a0792c8063f5
|
7
|
+
data.tar.gz: da59d2153f6ea5bb116ee44ae2dd7fd8cd8631c9024ebe7972d5103eb58f1fc05012953386d4520aed4247970dc00fc810ede2afc08a0ecc8329db053b3d5cb6
|
data/README.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# Fluxbit ViewComponents
|
2
2
|
|
3
|
+
     
|
4
|
+
|
5
|
+
|
6
|
+
|
3
7
|
Fluxbit ViewComponents is an implementation of the Fluxbit Design System using [ViewComponent](https://github.com/github/view_component).
|
4
8
|
|
5
9
|
<div style="text-align: center;">
|
@@ -8,7 +12,9 @@ Fluxbit ViewComponents is an implementation of the Fluxbit Design System using [
|
|
8
12
|
|
9
13
|
## Preview
|
10
14
|
|
11
|
-
|
15
|
+
We have a Lookbook app online to show the documentation and all the Components available in action!
|
16
|
+
|
17
|
+
Just [Click here!](https://fluxbit.artz.to)
|
12
18
|
|
13
19
|
## Usage
|
14
20
|
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The `Fluxbit::Form::CheckBoxComponent` is a form input component for check boxes and radio buttons.
|
4
|
+
# It extends `Fluxbit::Form::FieldComponent` and provides a styled checkbox/radio with label, helper text,
|
5
|
+
# and support for different visual states and groupings. It automatically adds the correct styles for both
|
6
|
+
# checkbox and radio types and works with or without Rails form builders.
|
7
|
+
#
|
8
|
+
# @example Basic usage
|
9
|
+
# = render Fluxbit::Form::CheckBoxComponent.new(name: :accept_terms, label: "Accept the terms")
|
10
|
+
#
|
11
|
+
# @see docs/03_Forms/CheckBox.md For detailed documentation and examples.
|
12
|
+
class Fluxbit::Form::CheckBoxComponent < Fluxbit::Form::FieldComponent
|
13
|
+
include Fluxbit::Config::Form::CheckBoxComponent
|
14
|
+
TYPE_DEFAULT = :check_box
|
15
|
+
TYPE_OPTIONS = %i[check_box checkbox radio_button].freeze
|
16
|
+
|
17
|
+
# Initializes the check box component with the given properties.
|
18
|
+
#
|
19
|
+
# @param name [String] Name of the field (required unless using form builder)
|
20
|
+
# @param label [String] Label text next to the input (optional)
|
21
|
+
# @param value [String] Value for the field (optional)
|
22
|
+
# @param type [String, Symbol] Input type (`"check_box"`, `"checkbox"`, `"radio_button"`)
|
23
|
+
# @param help_text [String] Helper or error text below the field
|
24
|
+
# @param disabled [Boolean] Disables the input if true
|
25
|
+
# @param checked [Boolean] Marks the input as checked if true
|
26
|
+
# @param class [String] Additional CSS classes for the input element
|
27
|
+
# @param ... any other HTML attribute supported by check_box_tag/radio_button_tag
|
28
|
+
def initialize(**props)
|
29
|
+
super(**props)
|
30
|
+
@type = options(@props.delete(:type), collection: TYPE_OPTIONS, default: TYPE_DEFAULT)
|
31
|
+
add(class: styles[:checkbox], to: @props, first_element: true) if @props[:type] == "checkbox"
|
32
|
+
add(class: styles[:base], to: @props, first_element: true)
|
33
|
+
end
|
34
|
+
|
35
|
+
def input
|
36
|
+
if @form.present? && @attribute.present?
|
37
|
+
@form.public_send(@type, @attribute, @props)
|
38
|
+
else
|
39
|
+
public_send("#{@type}_tag", @name, @value, @props)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def call
|
44
|
+
if @help_text
|
45
|
+
content_tag :div, { class: "flex" } do
|
46
|
+
concat content_tag(:div, input, { class: styles[:input_div] })
|
47
|
+
concat content_tag(:div, safe_join([ label, help_text ]), { class: styles[:helper_div] })
|
48
|
+
end
|
49
|
+
else
|
50
|
+
content_tag :div, { class: styles[:no_helper_div] } do
|
51
|
+
concat input
|
52
|
+
concat label
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -6,31 +6,32 @@ class Fluxbit::Form::Component < Fluxbit::Component
|
|
6
6
|
return @id ||= random_id if @props[:id].nil? && @form.nil?
|
7
7
|
return @props[:id] unless @props[:id].nil?
|
8
8
|
|
9
|
-
"#{@form.object_name}_#{@
|
9
|
+
"#{@form.object_name}_#{@attribute}"
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
13
|
-
return nil if
|
12
|
+
def define_help_text(help_text, object, attribute)
|
13
|
+
return nil if help_text.is_a? FalseClass
|
14
14
|
|
15
|
-
if
|
16
|
-
|
17
|
-
|
18
|
-
scope: [ :activerecord, :
|
15
|
+
if help_text.nil? && !object.nil? && !attribute.nil?
|
16
|
+
help_text = I18n.t(
|
17
|
+
attribute,
|
18
|
+
scope: [ :activerecord, :help_text, object.class.name.underscore.to_sym ],
|
19
19
|
default: nil
|
20
20
|
)
|
21
21
|
end
|
22
22
|
|
23
|
-
(
|
23
|
+
(help_text.is_a?(Array) ? help_text : [ help_text ]) + errors
|
24
24
|
end
|
25
25
|
|
26
|
-
def define_helper_popover(helper_popover, object,
|
27
|
-
return helper_popover if helper_popover != false && !helper_popover.nil?
|
26
|
+
def define_helper_popover(helper_popover, object, attribute)
|
27
|
+
return helper_popover if (helper_popover != false && !helper_popover.nil?) || object.nil?
|
28
28
|
|
29
|
-
|
29
|
+
object_name = object.class.name.underscore.to_sym
|
30
|
+
I18n.t(attribute, scope: [ :activerecord, :helper_popover, object_name ], default: nil)
|
30
31
|
end
|
31
32
|
|
32
|
-
def label_value(label, object,
|
33
|
-
return object.class.human_attribute_name(
|
33
|
+
def label_value(label, object, attribute, id)
|
34
|
+
return object.class.human_attribute_name(attribute) if label.nil? && !object.nil? && !attribute.nil?
|
34
35
|
return id.to_s.humanize if label.nil? && !id.nil?
|
35
36
|
return label unless label.nil?
|
36
37
|
|
@@ -52,20 +53,14 @@ class Fluxbit::Form::Component < Fluxbit::Component
|
|
52
53
|
def errors
|
53
54
|
return [] unless @object&.errors&.any?
|
54
55
|
|
55
|
-
@object.errors.filter { |f| f.attribute == @
|
56
|
+
@object.errors.filter { |f| f.attribute == @attribute }.map(&:full_message)
|
56
57
|
end
|
57
58
|
|
58
|
-
def
|
59
|
-
return "" if @
|
59
|
+
def help_text
|
60
|
+
return "" if @help_text.blank? || @help_text.compact.blank?
|
60
61
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
# end
|
65
|
-
# )
|
66
|
-
|
67
|
-
@helper_text.compact.map do |text|
|
68
|
-
concat Fluxbit::Form::HelperTextComponent.new(color: @color).with_content(text).render_in(view_context)
|
69
|
-
end
|
62
|
+
@help_text.compact.map do |text|
|
63
|
+
Fluxbit::Form::HelpTextComponent.new(color: @color).with_content(text).render_in(view_context)
|
64
|
+
end.join.html_safe
|
70
65
|
end
|
71
66
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
<%= content_tag :div, **@wrapper_html do %>
|
2
|
+
<div class="<%= self.styles[:base] %>">
|
3
|
+
<label for="<%= id %>" class="<%= self.styles[:label] %> <%= self.styles[:height][@height] %>">
|
4
|
+
<div class="<%= self.styles[:inner_div] %>">
|
5
|
+
<% if content? %>
|
6
|
+
<%= content %>
|
7
|
+
<% else %>
|
8
|
+
<%= create_icon %>
|
9
|
+
|
10
|
+
<% if @title != false %>
|
11
|
+
<p class="<%= self.styles[:title] %>">
|
12
|
+
<% if @title != true %>
|
13
|
+
<%= @title %>
|
14
|
+
<% else %>
|
15
|
+
<span class="font-semibold">Click to upload</span> or drag and drop
|
16
|
+
<% end %>
|
17
|
+
</p>
|
18
|
+
<% end %>
|
19
|
+
|
20
|
+
<% if @subtitle != false %>
|
21
|
+
<p class="<%= self.styles[:subtitle] %>">
|
22
|
+
<% if @subtitle != true %>
|
23
|
+
<%= @subtitle %>
|
24
|
+
<% else %>
|
25
|
+
SVG, PNG, JPG or GIF (MAX. 800x400px)
|
26
|
+
<% end %>
|
27
|
+
</p>
|
28
|
+
<% end %>
|
29
|
+
<% end %>
|
30
|
+
</div>
|
31
|
+
<% if @form.present? && @attribute.present? %>
|
32
|
+
<%= @form.file_field(@attribute, **@props) %>
|
33
|
+
<% else %>
|
34
|
+
<%= file_field_tag(@name, **@props) %>
|
35
|
+
<% end %>
|
36
|
+
</label>
|
37
|
+
</div>
|
38
|
+
<%= help_text %>
|
39
|
+
<% end %>
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The `Fluxbit::Form::DropzoneComponent` provides a drag-and-drop file input zone with support for labels,
|
4
|
+
# titles, subtitles, icons, validation states, and integration with Rails form builders.
|
5
|
+
# It renders a visually rich area that lets users drag files or click to select a file, and is fully customizable
|
6
|
+
# via its options and slot for custom content.
|
7
|
+
#
|
8
|
+
# @example Basic usage
|
9
|
+
# = render Fluxbit::Form::DropzoneComponent.new(name: :avatar)
|
10
|
+
#
|
11
|
+
# @see docs/03_Forms/Dropzone.md For detailed documentation and examples.
|
12
|
+
class Fluxbit::Form::DropzoneComponent < Fluxbit::Form::FieldComponent
|
13
|
+
include Fluxbit::Config::Form::DropzoneComponent
|
14
|
+
|
15
|
+
# Initializes the dropzone component with the given properties.
|
16
|
+
#
|
17
|
+
# @param name [String] Name of the field (required unless using form builder)
|
18
|
+
# @param label [String] Label for the input (optional)
|
19
|
+
# @param title [Boolean, String] Title text above the dropzone (true for default, false to hide, or custom string)
|
20
|
+
# @param subtitle [Boolean, String] Subtitle text below the title (true for default, false to hide, or custom string)
|
21
|
+
# @param icon [String, Symbol] Icon to display above the title (defaults to config)
|
22
|
+
# @param icon_props [Hash] Extra props for the icon element
|
23
|
+
# @param height [Integer] Height preset (0: auto, 1: h-32, 2: h-64, 3: h-96; default is 0)
|
24
|
+
# @param help_text [String] Helper or error text below the field
|
25
|
+
# @param ... any other HTML attribute supported by file_field_tag
|
26
|
+
def initialize(**props)
|
27
|
+
super(**props)
|
28
|
+
@title = options(@props.delete(:title), default: true)
|
29
|
+
@subtitle = options(@props.delete(:subtitle), default: true)
|
30
|
+
@icon = @props.delete(:icon) || @@icon
|
31
|
+
@icon_props = @props.delete(:icon_props) || { class: styles[:icon] }
|
32
|
+
@height = @props.delete(:height) || @@height
|
33
|
+
add to: @props, class: "hidden"
|
34
|
+
end
|
35
|
+
|
36
|
+
def create_icon
|
37
|
+
anyicon(icon: @icon, class: styles[:icon])
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Fluxbit::Form::FieldComponent < Fluxbit::Form::Component
|
4
|
+
def initialize(**props)
|
5
|
+
super
|
6
|
+
@props = props
|
7
|
+
@form = @props.delete(:form)
|
8
|
+
@attribute = @props.delete(:attribute)
|
9
|
+
@name = @props.delete(:name) || (@attribute if @form.present?)
|
10
|
+
@value = @props.delete(:value)
|
11
|
+
@id = @props.delete(:id)
|
12
|
+
|
13
|
+
@object = @form&.object
|
14
|
+
@help_text = define_help_text(props.delete(:help_text), @object, @attribute)
|
15
|
+
@helper_popover = define_helper_popover(props.delete(:helper_popover), @object, @attribute)
|
16
|
+
@helper_popover_placement = props.delete(:helper_popover_placement) || "right"
|
17
|
+
@label = label_value(props.delete(:label), @object, @attribute, @id)
|
18
|
+
@wrapper_html = props.delete(:wrapper_html) || {}
|
19
|
+
define_wrapper_options
|
20
|
+
end
|
21
|
+
|
22
|
+
def define_wrapper_options
|
23
|
+
add(to: @wrapper_html, class: "required") if @props[:required].present?
|
24
|
+
add(to: @wrapper_html, class: @name) if @name.present?
|
25
|
+
end
|
26
|
+
end
|
@@ -79,6 +79,7 @@ class Fluxbit::Form::FormBuilderComponent < Fluxbit::Component
|
|
79
79
|
else
|
80
80
|
''
|
81
81
|
end}#{element_type(kwargs[:type])}Component".constantize
|
82
|
+
|
82
83
|
unless kwargs[:with_content]
|
83
84
|
return content_tag(:div, render(component_klass.new(**kwargs), &block), class: outer_div)
|
84
85
|
end
|
@@ -88,7 +89,7 @@ class Fluxbit::Form::FormBuilderComponent < Fluxbit::Component
|
|
88
89
|
end
|
89
90
|
|
90
91
|
def element_type(type)
|
91
|
-
return "
|
92
|
+
return "TextField" if type.nil? || type.to_s.in?(TEXT_TYPES)
|
92
93
|
return type.to_s.concat("_input").camelcase if type.to_s.in?(INPUT_TYPES)
|
93
94
|
|
94
95
|
case type
|
@@ -104,14 +105,11 @@ class Fluxbit::Form::FormBuilderComponent < Fluxbit::Component
|
|
104
105
|
def generate_elements
|
105
106
|
return elements if elements?
|
106
107
|
|
107
|
-
safe_join(
|
108
|
-
end
|
109
|
-
|
110
|
-
def generate_div
|
111
|
-
safe_join errors?, content_tag(:div, generate_elements, @props)
|
108
|
+
safe_join(@elements.map { |element| choose_element(element.merge({ form: @form }), nil) })
|
112
109
|
end
|
113
110
|
|
114
111
|
def call
|
115
|
-
|
112
|
+
elements_rendered = elements? ? elements : safe_join(@elements.map { |element| choose_element(element.merge({ form: @form }), nil) })
|
113
|
+
safe_join [ errors?, content_tag(:div, elements_rendered, @props) ]
|
116
114
|
end
|
117
115
|
end
|
@@ -1,11 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# The `Fluxbit::
|
3
|
+
# The `Fluxbit::HelpTextComponent` is a component for rendering customizable helper text elements.
|
4
4
|
# It extends `Fluxbit::Component` and provides options for configuring the helper text's
|
5
5
|
# appearance and behavior. You can control the helper text's color and other attributes.
|
6
6
|
# The helper text can have various styles applied based on the provided properties.
|
7
|
-
|
8
|
-
|
7
|
+
#
|
8
|
+
# @example Basic usage
|
9
|
+
# = render Fluxbit::Form::HelpTextComponent.new { "Your password must be at least 8 characters." }
|
10
|
+
#
|
11
|
+
# @see docs/03_Forms/HelpText.md For detailed documentation and examples.
|
12
|
+
class Fluxbit::Form::HelpTextComponent < Fluxbit::Form::Component
|
13
|
+
include Fluxbit::Config::Form::HelpTextComponent
|
9
14
|
|
10
15
|
# Initializes the helper text component with the given properties.
|
11
16
|
#
|
@@ -1,36 +1,39 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# The `Fluxbit::Form::LabelComponent` is a flexible and accessible label for form fields.
|
4
|
+
# It supports custom content, helper popovers, multiple color styles, sizing options, and
|
5
|
+
# displays associated help text when provided. It is fully compatible with Rails form builders.
|
6
|
+
#
|
7
|
+
# @example Basic usage
|
8
|
+
# = render Fluxbit::Form::LabelComponent.new(with_content: "Your Name")
|
9
|
+
#
|
10
|
+
# @see docs/03_Forms/Label.md For detailed documentation and examples.
|
3
11
|
class Fluxbit::Form::LabelComponent < Fluxbit::Form::Component
|
4
|
-
|
5
|
-
{
|
6
|
-
base: "flex font-medium",
|
7
|
-
colors: {
|
8
|
-
default: "text-gray-900 dark:text-white",
|
9
|
-
success: "text-green-700 dark:text-green-500",
|
10
|
-
failure: "text-red-700 dark:text-red-500",
|
11
|
-
info: "text-cyan-500 dark:text-cyan-600",
|
12
|
-
warning: "text-yellow-500 dark:text-yellow-600"
|
13
|
-
},
|
14
|
-
sizes: {
|
15
|
-
sm: "text-sm",
|
16
|
-
md: "text-md",
|
17
|
-
lg: "text-lg"
|
18
|
-
},
|
19
|
-
helper_popover: "px-2 text-slate-400"
|
20
|
-
}
|
21
|
-
end
|
12
|
+
include Fluxbit::Config::Form::LabelComponent
|
22
13
|
|
23
|
-
|
24
|
-
|
14
|
+
# Initializes the label component with the given properties.
|
15
|
+
#
|
16
|
+
# @param with_content [String] The label text to display (alternative to block content)
|
17
|
+
# @param help_text [String, Array<String>] One or more help text messages to render below the label
|
18
|
+
# @param helper_popover [String] Popover content shown on icon hover
|
19
|
+
# @param helper_popover_placement [String] Placement of the popover (default: "right")
|
20
|
+
# @param sizing [Integer] Size index for label text (default: config default)
|
21
|
+
# @param color [Symbol] Label color (:default, :success, :failure, :info, :warning)
|
22
|
+
# @param class [String] Additional CSS classes for the label element
|
23
|
+
# @param ... any other HTML attribute supported by the <label> tag
|
24
|
+
def initialize(**props)
|
25
25
|
super
|
26
26
|
@props = props
|
27
|
-
@
|
28
|
-
@
|
29
|
-
@
|
30
|
-
@helper_popover = helper_popover
|
31
|
-
@helper_popover_placement = helper_popover_placement
|
32
|
-
|
33
|
-
|
27
|
+
@with_content = @props.delete(:with_content)
|
28
|
+
@help_text = @props.delete(:help_text)
|
29
|
+
@help_text = [ @help_text ] if !@help_text.is_a?(Array)
|
30
|
+
@helper_popover = @props.delete(:helper_popover)
|
31
|
+
@helper_popover_placement = @props.delete(:helper_popover_placement) || @@helper_popover_placement
|
32
|
+
@sizing = @props[:sizing].to_i || @@sizing
|
33
|
+
@sizing = (styles[:sizes].count - 1) if @sizing > (styles[:sizes].count - 1)
|
34
|
+
@color = options(@props.delete(:color), collection: styles[:colors], default: @@color)
|
35
|
+
|
36
|
+
add class: styles[:colors][@color], to: @props, first_element: true
|
34
37
|
add class: styles[:base], to: @props, first_element: true
|
35
38
|
add class: styles[:sizes][@sizing], to: @props, first_element: true
|
36
39
|
end
|
@@ -39,7 +42,7 @@ class Fluxbit::Form::LabelComponent < Fluxbit::Form::Component
|
|
39
42
|
return "" if @helper_popover.nil?
|
40
43
|
|
41
44
|
content_tag :span,
|
42
|
-
anyicon(icon:
|
45
|
+
anyicon(icon: @@helper_popover_icon, class: @@helper_popover_icon_class),
|
43
46
|
{
|
44
47
|
"data-popover-placement": @helper_popover_placement,
|
45
48
|
"data-popover-target": target,
|
@@ -57,7 +60,7 @@ class Fluxbit::Form::LabelComponent < Fluxbit::Form::Component
|
|
57
60
|
safe_join(
|
58
61
|
[
|
59
62
|
content_tag(:label, safe_join([ content || @with_content, span_helper_popover ]), @props),
|
60
|
-
|
63
|
+
help_text,
|
61
64
|
render_popover
|
62
65
|
]
|
63
66
|
)
|
@@ -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,88 @@
|
|
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] Label for the input (optional)
|
16
|
+
# @param value [String] Value for the field (optional)
|
17
|
+
# @param grouped [Boolean] Enables grouped select options (default: false)
|
18
|
+
# @param time_zone [Boolean] Uses Rails time zone select options (default: false)
|
19
|
+
# @param select_options [Hash] Options for select tag (prompt, selected, disabled, etc)
|
20
|
+
# @param choices [Array] List of choices for options (alternative to options)
|
21
|
+
# @param options [Array, Hash] List or hash of options (or groups if grouped)
|
22
|
+
# @param help_text [String] Helper or error text below the field
|
23
|
+
# @param class [String] Additional CSS classes for the select element
|
24
|
+
# @param ... any other HTML attribute supported by <select>
|
25
|
+
def initialize(**props)
|
26
|
+
super(**props)
|
27
|
+
@grouped = @props.delete(:grouped) || false
|
28
|
+
@time_zone = @props.delete(:time_zone) || false
|
29
|
+
@select_options = @props.delete(:select_options) || {}
|
30
|
+
@choices = @props.delete(:choices) || nil
|
31
|
+
@options = @props.delete(:options) || {}
|
32
|
+
@options = ::ActiveSupport::TimeZone.all if @time_zone
|
33
|
+
end
|
34
|
+
|
35
|
+
def input
|
36
|
+
if @form.present? && @attribute.present?
|
37
|
+
@form.select(
|
38
|
+
@attribute,
|
39
|
+
build_options_for_select,
|
40
|
+
@select_options,
|
41
|
+
@props
|
42
|
+
)
|
43
|
+
else
|
44
|
+
select_tag(
|
45
|
+
@name,
|
46
|
+
build_options_for_select,
|
47
|
+
@props
|
48
|
+
)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def build_options_for_select
|
53
|
+
if @grouped
|
54
|
+
grouped_options_for_select(
|
55
|
+
@options,
|
56
|
+
@selected,
|
57
|
+
disabled: @disabled_options,
|
58
|
+
prompt: @prompt,
|
59
|
+
divider: @divider
|
60
|
+
)
|
61
|
+
elsif @time_zone
|
62
|
+
time_zone_options_for_select(@selected)
|
63
|
+
else
|
64
|
+
options_for_select(@options, selected: @selected, disabled: @disabled_options)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def grouped_selected_option
|
71
|
+
@options.each do |group|
|
72
|
+
group_to_traverse = @divider ? group[1] : group
|
73
|
+
if group_to_traverse.is_a?(String)
|
74
|
+
return group_to_traverse if group_to_traverse == @selected.to_s
|
75
|
+
|
76
|
+
next
|
77
|
+
end
|
78
|
+
|
79
|
+
group_to_traverse.each do |item|
|
80
|
+
if item.is_a?(Array) && item[1] == @selected.to_s
|
81
|
+
return item[0]
|
82
|
+
elsif item.is_a?(String) && item == @selected.to_s
|
83
|
+
return item
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|