better_ui 0.6.0 → 0.7.1
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 +257 -212
- data/Rakefile +11 -2
- data/app/components/better_ui/action_messages_component/action_messages_component.html.erb +48 -0
- data/app/components/better_ui/action_messages_component.rb +544 -0
- data/app/components/better_ui/application_component.rb +66 -0
- data/app/components/better_ui/button_component/button_component.html.erb +31 -0
- data/app/components/better_ui/button_component.rb +307 -0
- data/app/components/better_ui/card_component/card_component.html.erb +17 -0
- data/app/components/better_ui/card_component.rb +460 -0
- data/app/components/better_ui/drawer/header_component/header_component.html.erb +24 -0
- data/app/components/better_ui/drawer/header_component.rb +238 -0
- data/app/components/better_ui/drawer/layout_component/layout_component.html.erb +44 -0
- data/app/components/better_ui/drawer/layout_component.rb +270 -0
- data/app/components/better_ui/drawer/nav_group_component/nav_group_component.html.erb +10 -0
- data/app/components/better_ui/drawer/nav_group_component.rb +155 -0
- data/app/components/better_ui/drawer/nav_item_component/nav_item_component.html.erb +13 -0
- data/app/components/better_ui/drawer/nav_item_component.rb +225 -0
- data/app/components/better_ui/drawer/sidebar_component/sidebar_component.html.erb +17 -0
- data/app/components/better_ui/drawer/sidebar_component.rb +263 -0
- data/app/components/better_ui/forms/base_component.rb +450 -0
- data/app/components/better_ui/forms/checkbox_component/checkbox_component.html.erb +28 -0
- data/app/components/better_ui/forms/checkbox_component.rb +419 -0
- data/app/components/better_ui/forms/checkbox_group_component/checkbox_group_component.html.erb +40 -0
- data/app/components/better_ui/forms/checkbox_group_component.rb +363 -0
- data/app/components/better_ui/forms/number_input_component/number_input_component.html.erb +40 -0
- data/app/components/better_ui/forms/number_input_component.rb +320 -0
- data/app/components/better_ui/forms/password_input_component/password_input_component.html.erb +71 -0
- data/app/components/better_ui/forms/password_input_component.rb +206 -0
- data/app/components/better_ui/forms/text_input_component/text_input_component.html.erb +40 -0
- data/app/components/better_ui/forms/text_input_component.rb +258 -0
- data/app/components/better_ui/forms/textarea_component/textarea_component.html.erb +40 -0
- data/app/components/better_ui/forms/textarea_component.rb +329 -0
- data/app/form_builders/better_ui/ui_form_builder.rb +467 -0
- data/app/helpers/better_ui/application_helper.rb +325 -58
- data/app/views/layouts/better_ui/application.html.erb +1 -1
- data/config/routes.rb +1 -0
- data/lib/better_ui/engine.rb +34 -5
- data/lib/better_ui/version.rb +1 -1
- data/lib/better_ui.rb +32 -5
- data/lib/generators/better_ui/install/USAGE +44 -0
- data/lib/generators/better_ui/install/install_generator.rb +87 -0
- data/lib/generators/better_ui/install/templates/better_ui_theme.css.tt +280 -0
- data/lib/tasks/better_ui_tasks.rake +39 -4
- metadata +55 -203
- data/app/components/better_ui/application/card/component.html.erb +0 -20
- data/app/components/better_ui/application/card/component.rb +0 -214
- data/app/components/better_ui/application/main/component.html.erb +0 -9
- data/app/components/better_ui/application/main/component.rb +0 -123
- data/app/components/better_ui/application/navbar/component.html.erb +0 -92
- data/app/components/better_ui/application/navbar/component.rb +0 -136
- data/app/components/better_ui/application/sidebar/component.html.erb +0 -249
- data/app/components/better_ui/application/sidebar/component.rb +0 -187
- data/app/components/better_ui/general/accordion/component.html.erb +0 -5
- data/app/components/better_ui/general/accordion/component.rb +0 -92
- data/app/components/better_ui/general/accordion/item_component.html.erb +0 -12
- data/app/components/better_ui/general/accordion/item_component.rb +0 -176
- data/app/components/better_ui/general/alert/component.html.erb +0 -32
- data/app/components/better_ui/general/alert/component.rb +0 -242
- data/app/components/better_ui/general/avatar/component.html.erb +0 -20
- data/app/components/better_ui/general/avatar/component.rb +0 -301
- data/app/components/better_ui/general/badge/component.html.erb +0 -23
- data/app/components/better_ui/general/badge/component.rb +0 -248
- data/app/components/better_ui/general/breadcrumb/component.html.erb +0 -15
- data/app/components/better_ui/general/breadcrumb/component.rb +0 -187
- data/app/components/better_ui/general/button/component.html.erb +0 -34
- data/app/components/better_ui/general/button/component.rb +0 -214
- data/app/components/better_ui/general/divider/component.html.erb +0 -10
- data/app/components/better_ui/general/divider/component.rb +0 -226
- data/app/components/better_ui/general/dropdown/component.html.erb +0 -28
- data/app/components/better_ui/general/dropdown/component.rb +0 -192
- data/app/components/better_ui/general/dropdown/divider_component.html.erb +0 -1
- data/app/components/better_ui/general/dropdown/divider_component.rb +0 -41
- data/app/components/better_ui/general/dropdown/item_component.html.erb +0 -6
- data/app/components/better_ui/general/dropdown/item_component.rb +0 -119
- data/app/components/better_ui/general/field/component.html.erb +0 -27
- data/app/components/better_ui/general/field/component.rb +0 -37
- data/app/components/better_ui/general/grid/cell_component.html.erb +0 -3
- data/app/components/better_ui/general/grid/cell_component.rb +0 -390
- data/app/components/better_ui/general/grid/component.html.erb +0 -3
- data/app/components/better_ui/general/grid/component.rb +0 -301
- data/app/components/better_ui/general/heading/component.html.erb +0 -22
- data/app/components/better_ui/general/heading/component.rb +0 -257
- data/app/components/better_ui/general/icon/component.html.erb +0 -7
- data/app/components/better_ui/general/icon/component.rb +0 -240
- data/app/components/better_ui/general/input/checkbox/component.html.erb +0 -5
- data/app/components/better_ui/general/input/checkbox/component.rb +0 -238
- data/app/components/better_ui/general/input/datetime/component.html.erb +0 -5
- data/app/components/better_ui/general/input/datetime/component.rb +0 -223
- data/app/components/better_ui/general/input/pin/component.html.erb +0 -1
- data/app/components/better_ui/general/input/pin/component.rb +0 -201
- data/app/components/better_ui/general/input/radio/component.html.erb +0 -5
- data/app/components/better_ui/general/input/radio/component.rb +0 -230
- data/app/components/better_ui/general/input/rating/component.html.erb +0 -4
- data/app/components/better_ui/general/input/rating/component.rb +0 -272
- data/app/components/better_ui/general/input/select/component.html.erb +0 -78
- data/app/components/better_ui/general/input/select/component.rb +0 -249
- data/app/components/better_ui/general/input/select/select_component.html.erb +0 -5
- data/app/components/better_ui/general/input/select/select_component.rb +0 -37
- data/app/components/better_ui/general/input/text/component.html.erb +0 -5
- data/app/components/better_ui/general/input/text/component.rb +0 -171
- data/app/components/better_ui/general/input/textarea/component.html.erb +0 -5
- data/app/components/better_ui/general/input/textarea/component.rb +0 -166
- data/app/components/better_ui/general/input/toggle/component.html.erb +0 -5
- data/app/components/better_ui/general/input/toggle/component.rb +0 -242
- data/app/components/better_ui/general/link/component.html.erb +0 -18
- data/app/components/better_ui/general/link/component.rb +0 -258
- data/app/components/better_ui/general/modal/component.html.erb +0 -5
- data/app/components/better_ui/general/modal/component.rb +0 -47
- data/app/components/better_ui/general/modal/modal_component.html.erb +0 -52
- data/app/components/better_ui/general/modal/modal_component.rb +0 -160
- data/app/components/better_ui/general/pagination/component.html.erb +0 -85
- data/app/components/better_ui/general/pagination/component.rb +0 -216
- data/app/components/better_ui/general/panel/component.html.erb +0 -28
- data/app/components/better_ui/general/panel/component.rb +0 -249
- data/app/components/better_ui/general/progress/component.html.erb +0 -11
- data/app/components/better_ui/general/progress/component.rb +0 -160
- data/app/components/better_ui/general/spinner/component.html.erb +0 -35
- data/app/components/better_ui/general/spinner/component.rb +0 -93
- data/app/components/better_ui/general/table/component.html.erb +0 -5
- data/app/components/better_ui/general/table/component.rb +0 -217
- data/app/components/better_ui/general/table/tbody_component.html.erb +0 -3
- data/app/components/better_ui/general/table/tbody_component.rb +0 -30
- data/app/components/better_ui/general/table/td_component.html.erb +0 -3
- data/app/components/better_ui/general/table/td_component.rb +0 -44
- data/app/components/better_ui/general/table/tfoot_component.html.erb +0 -3
- data/app/components/better_ui/general/table/tfoot_component.rb +0 -28
- data/app/components/better_ui/general/table/th_component.html.erb +0 -6
- data/app/components/better_ui/general/table/th_component.rb +0 -51
- data/app/components/better_ui/general/table/thead_component.html.erb +0 -3
- data/app/components/better_ui/general/table/thead_component.rb +0 -28
- data/app/components/better_ui/general/table/tr_component.html.erb +0 -3
- data/app/components/better_ui/general/table/tr_component.rb +0 -30
- data/app/components/better_ui/general/tabs/component.html.erb +0 -11
- data/app/components/better_ui/general/tabs/component.rb +0 -120
- data/app/components/better_ui/general/tabs/panel_component.html.erb +0 -3
- data/app/components/better_ui/general/tabs/panel_component.rb +0 -37
- data/app/components/better_ui/general/tabs/tab_component.html.erb +0 -13
- data/app/components/better_ui/general/tabs/tab_component.rb +0 -111
- data/app/components/better_ui/general/tag/component.html.erb +0 -3
- data/app/components/better_ui/general/tag/component.rb +0 -104
- data/app/components/better_ui/general/text/component.html.erb +0 -1
- data/app/components/better_ui/general/text/component.rb +0 -194
- data/app/components/better_ui/general/tooltip/component.html.erb +0 -7
- data/app/components/better_ui/general/tooltip/component.rb +0 -239
- data/app/helpers/better_ui/application/components/card/card_helper.rb +0 -96
- data/app/helpers/better_ui/application/components/card.rb +0 -11
- data/app/helpers/better_ui/application/components/main/main_helper.rb +0 -64
- data/app/helpers/better_ui/application/components/navbar/navbar_helper.rb +0 -77
- data/app/helpers/better_ui/application/components/sidebar/sidebar_helper.rb +0 -51
- data/app/helpers/better_ui/general/components/accordion/accordion_helper.rb +0 -73
- data/app/helpers/better_ui/general/components/alert/alert_helper.rb +0 -57
- data/app/helpers/better_ui/general/components/avatar/avatar_helper.rb +0 -29
- data/app/helpers/better_ui/general/components/badge/badge_helper.rb +0 -53
- data/app/helpers/better_ui/general/components/breadcrumb/breadcrumb_helper.rb +0 -37
- data/app/helpers/better_ui/general/components/button/button_helper.rb +0 -65
- data/app/helpers/better_ui/general/components/container/container_helper.rb +0 -60
- data/app/helpers/better_ui/general/components/divider/divider_helper.rb +0 -63
- data/app/helpers/better_ui/general/components/dropdown/divider_helper.rb +0 -32
- data/app/helpers/better_ui/general/components/dropdown/dropdown_helper.rb +0 -88
- data/app/helpers/better_ui/general/components/dropdown/item_helper.rb +0 -68
- data/app/helpers/better_ui/general/components/field/field_helper.rb +0 -26
- data/app/helpers/better_ui/general/components/grid/grid_helper.rb +0 -145
- data/app/helpers/better_ui/general/components/heading/heading_helper.rb +0 -72
- data/app/helpers/better_ui/general/components/icon/icon_helper.rb +0 -16
- data/app/helpers/better_ui/general/components/input/checkbox/checkbox_helper.rb +0 -81
- data/app/helpers/better_ui/general/components/input/datetime/datetime_helper.rb +0 -91
- data/app/helpers/better_ui/general/components/input/pin/pin_helper.rb +0 -76
- data/app/helpers/better_ui/general/components/input/radio/radio_helper.rb +0 -79
- data/app/helpers/better_ui/general/components/input/radio_group/radio_group_helper.rb +0 -124
- data/app/helpers/better_ui/general/components/input/rating/rating_helper.rb +0 -70
- data/app/helpers/better_ui/general/components/input/select/select_helper.rb +0 -86
- data/app/helpers/better_ui/general/components/input/text/text_helper.rb +0 -138
- data/app/helpers/better_ui/general/components/input/textarea/textarea_helper.rb +0 -73
- data/app/helpers/better_ui/general/components/input/toggle/toggle_helper.rb +0 -77
- data/app/helpers/better_ui/general/components/link/link_helper.rb +0 -89
- data/app/helpers/better_ui/general/components/modal/modal_helper.rb +0 -85
- data/app/helpers/better_ui/general/components/pagination/pagination_helper.rb +0 -82
- data/app/helpers/better_ui/general/components/panel/panel_helper.rb +0 -83
- data/app/helpers/better_ui/general/components/progress/progress_helper.rb +0 -53
- data/app/helpers/better_ui/general/components/spinner/spinner_helper.rb +0 -19
- data/app/helpers/better_ui/general/components/table/table_helper.rb +0 -53
- data/app/helpers/better_ui/general/components/table/tbody_helper.rb +0 -13
- data/app/helpers/better_ui/general/components/table/td_helper.rb +0 -19
- data/app/helpers/better_ui/general/components/table/tfoot_helper.rb +0 -13
- data/app/helpers/better_ui/general/components/table/th_helper.rb +0 -19
- data/app/helpers/better_ui/general/components/table/thead_helper.rb +0 -13
- data/app/helpers/better_ui/general/components/table/tr_helper.rb +0 -13
- data/app/helpers/better_ui/general/components/tabs/panel_helper.rb +0 -62
- data/app/helpers/better_ui/general/components/tabs/tab_helper.rb +0 -55
- data/app/helpers/better_ui/general/components/tabs/tabs_helper.rb +0 -95
- data/app/helpers/better_ui/general/components/tag/tag_helper.rb +0 -26
- data/app/helpers/better_ui/general/components/text/text_helper.rb +0 -83
- data/app/helpers/better_ui/general/components/tooltip/tooltip_helper.rb +0 -60
- data/app/jobs/better_ui/application_job.rb +0 -4
- data/app/mailers/better_ui/application_mailer.rb +0 -6
- data/config/initializers/lookbook.rb +0 -23
- data/lib/better_ui/railtie.rb +0 -20
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BetterUi
|
|
4
|
+
module Forms
|
|
5
|
+
# A checkbox group component for selecting multiple options from a collection.
|
|
6
|
+
#
|
|
7
|
+
# This component renders a group of checkboxes within a fieldset, allowing users
|
|
8
|
+
# to select multiple values. It supports both vertical and horizontal orientations,
|
|
9
|
+
# and integrates seamlessly with Rails form builders for array attribute submission.
|
|
10
|
+
#
|
|
11
|
+
# @example Basic checkbox group
|
|
12
|
+
# <%= render BetterUi::Forms::CheckboxGroupComponent.new(
|
|
13
|
+
# name: "user[roles]",
|
|
14
|
+
# collection: ["Admin", "Editor", "Viewer"],
|
|
15
|
+
# legend: "User Roles"
|
|
16
|
+
# ) %>
|
|
17
|
+
#
|
|
18
|
+
# @example With label/value pairs
|
|
19
|
+
# <%= render BetterUi::Forms::CheckboxGroupComponent.new(
|
|
20
|
+
# name: "user[permissions]",
|
|
21
|
+
# collection: [["Read", "read"], ["Write", "write"], ["Delete", "delete"]],
|
|
22
|
+
# selected: ["read", "write"],
|
|
23
|
+
# legend: "Permissions"
|
|
24
|
+
# ) %>
|
|
25
|
+
#
|
|
26
|
+
# @example Horizontal orientation
|
|
27
|
+
# <%= render BetterUi::Forms::CheckboxGroupComponent.new(
|
|
28
|
+
# name: "options",
|
|
29
|
+
# collection: ["Option A", "Option B", "Option C"],
|
|
30
|
+
# orientation: :horizontal
|
|
31
|
+
# ) %>
|
|
32
|
+
#
|
|
33
|
+
# @example With validation errors
|
|
34
|
+
# <%= render BetterUi::Forms::CheckboxGroupComponent.new(
|
|
35
|
+
# name: "user[interests]",
|
|
36
|
+
# collection: ["Sports", "Music", "Art"],
|
|
37
|
+
# errors: ["Please select at least one interest"]
|
|
38
|
+
# ) %>
|
|
39
|
+
#
|
|
40
|
+
# @example Using with Rails form builder
|
|
41
|
+
# <%= form_with model: @user, builder: BetterUi::UiFormBuilder do |f| %>
|
|
42
|
+
# <%= f.bui_checkbox_group :roles, [["Admin", "admin"], ["Editor", "editor"]] %>
|
|
43
|
+
# <% end %>
|
|
44
|
+
#
|
|
45
|
+
# @see CheckboxComponent
|
|
46
|
+
# @see BetterUi::UiFormBuilder#bui_checkbox_group
|
|
47
|
+
class CheckboxGroupComponent < ApplicationComponent
|
|
48
|
+
# Available size variants for checkbox groups.
|
|
49
|
+
# Each size adjusts checkbox dimensions and spacing proportionally.
|
|
50
|
+
#
|
|
51
|
+
# @return [Array<Symbol>] the list of valid size options (:xs, :sm, :md, :lg, :xl)
|
|
52
|
+
SIZES = %i[xs sm md lg xl].freeze
|
|
53
|
+
|
|
54
|
+
# Available orientation options for checkbox group layout.
|
|
55
|
+
#
|
|
56
|
+
# @return [Array<Symbol>] the list of valid orientations (:vertical, :horizontal)
|
|
57
|
+
ORIENTATIONS = %i[vertical horizontal].freeze
|
|
58
|
+
|
|
59
|
+
# Initializes a new checkbox group component.
|
|
60
|
+
#
|
|
61
|
+
# @param name [String] the base name attribute for the checkboxes (required for form submission)
|
|
62
|
+
# @param collection [Array] the collection of options, can be:
|
|
63
|
+
# - Array of values (e.g., ["Admin", "Editor"])
|
|
64
|
+
# - Array of [label, value] pairs (e.g., [["Admin", "admin"], ["Editor", "editor"]])
|
|
65
|
+
# @param selected [Array, String, nil] the currently selected value(s)
|
|
66
|
+
# @param legend [String, nil] the legend text for the fieldset
|
|
67
|
+
# @param hint [String, nil] helpful hint text displayed below the checkboxes
|
|
68
|
+
# @param variant [Symbol] the color variant for all checkboxes (:primary, :secondary, etc.)
|
|
69
|
+
# @param size [Symbol] the size variant (:xs, :sm, :md, :lg, :xl), defaults to :md
|
|
70
|
+
# @param orientation [Symbol] the layout orientation (:vertical, :horizontal), defaults to :vertical
|
|
71
|
+
# @param disabled [Boolean] whether all checkboxes should be disabled, defaults to false
|
|
72
|
+
# @param required [Boolean] whether the field is required (shows asterisk indicator), defaults to false
|
|
73
|
+
# @param errors [Array<String>, String, nil] validation error messages to display
|
|
74
|
+
# @param container_classes [String, Array<String>, nil] additional CSS classes for the outer wrapper
|
|
75
|
+
# @param legend_classes [String, Array<String>, nil] additional CSS classes for the legend element
|
|
76
|
+
# @param items_classes [String, Array<String>, nil] additional CSS classes for the items container
|
|
77
|
+
# @param hint_classes [String, Array<String>, nil] additional CSS classes for the hint text
|
|
78
|
+
# @param error_classes [String, Array<String>, nil] additional CSS classes for error messages
|
|
79
|
+
# @param options [Hash] additional HTML attributes to pass through to the fieldset element
|
|
80
|
+
#
|
|
81
|
+
# @raise [ArgumentError] if variant, size, or orientation is invalid
|
|
82
|
+
def initialize(
|
|
83
|
+
name:,
|
|
84
|
+
collection: [],
|
|
85
|
+
selected: [],
|
|
86
|
+
legend: nil,
|
|
87
|
+
hint: nil,
|
|
88
|
+
variant: :primary,
|
|
89
|
+
size: :md,
|
|
90
|
+
orientation: :vertical,
|
|
91
|
+
disabled: false,
|
|
92
|
+
required: false,
|
|
93
|
+
errors: nil,
|
|
94
|
+
container_classes: nil,
|
|
95
|
+
legend_classes: nil,
|
|
96
|
+
items_classes: nil,
|
|
97
|
+
hint_classes: nil,
|
|
98
|
+
error_classes: nil,
|
|
99
|
+
**options
|
|
100
|
+
)
|
|
101
|
+
@name = name
|
|
102
|
+
@collection = collection
|
|
103
|
+
@selected = Array(selected).map(&:to_s)
|
|
104
|
+
@legend = legend
|
|
105
|
+
@hint = hint
|
|
106
|
+
@variant = validate_variant(variant)
|
|
107
|
+
@size = validate_size(size)
|
|
108
|
+
@orientation = validate_orientation(orientation)
|
|
109
|
+
@disabled = disabled
|
|
110
|
+
@required = required
|
|
111
|
+
@errors = Array(errors).compact.reject(&:blank?)
|
|
112
|
+
@container_classes = container_classes
|
|
113
|
+
@legend_classes = legend_classes
|
|
114
|
+
@items_classes = items_classes
|
|
115
|
+
@hint_classes = hint_classes
|
|
116
|
+
@error_classes = error_classes
|
|
117
|
+
@options = options
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
private
|
|
121
|
+
|
|
122
|
+
# Validates that the provided variant is one of the allowed VARIANTS.
|
|
123
|
+
#
|
|
124
|
+
# @param variant [Symbol] the variant to validate
|
|
125
|
+
# @return [Symbol] the validated variant
|
|
126
|
+
# @raise [ArgumentError] if variant is not in VARIANTS
|
|
127
|
+
# @api private
|
|
128
|
+
def validate_variant(variant)
|
|
129
|
+
unless BetterUi::ApplicationComponent::VARIANTS.key?(variant)
|
|
130
|
+
raise ArgumentError, "Invalid variant: #{variant}. Must be one of: #{BetterUi::ApplicationComponent::VARIANTS.keys.join(', ')}"
|
|
131
|
+
end
|
|
132
|
+
variant
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Validates that the provided size is one of the allowed SIZES.
|
|
136
|
+
#
|
|
137
|
+
# @param size [Symbol] the size to validate
|
|
138
|
+
# @return [Symbol] the validated size
|
|
139
|
+
# @raise [ArgumentError] if size is not in SIZES
|
|
140
|
+
# @api private
|
|
141
|
+
def validate_size(size)
|
|
142
|
+
unless SIZES.include?(size)
|
|
143
|
+
raise ArgumentError, "Invalid size: #{size}. Must be one of: #{SIZES.join(', ')}"
|
|
144
|
+
end
|
|
145
|
+
size
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Validates that the provided orientation is one of the allowed ORIENTATIONS.
|
|
149
|
+
#
|
|
150
|
+
# @param orientation [Symbol] the orientation to validate
|
|
151
|
+
# @return [Symbol] the validated orientation
|
|
152
|
+
# @raise [ArgumentError] if orientation is not in ORIENTATIONS
|
|
153
|
+
# @api private
|
|
154
|
+
def validate_orientation(orientation)
|
|
155
|
+
unless ORIENTATIONS.include?(orientation)
|
|
156
|
+
raise ArgumentError, "Invalid orientation: #{orientation}. Must be one of: #{ORIENTATIONS.join(', ')}"
|
|
157
|
+
end
|
|
158
|
+
orientation
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Checks if the component has any validation errors to display.
|
|
162
|
+
#
|
|
163
|
+
# @return [Boolean] true if errors are present, false otherwise
|
|
164
|
+
# @api private
|
|
165
|
+
def has_errors?
|
|
166
|
+
@errors.present?
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Returns the field name for checkbox inputs (with array notation).
|
|
170
|
+
#
|
|
171
|
+
# @return [String] the field name with [] suffix for array submission
|
|
172
|
+
# @api private
|
|
173
|
+
def field_name
|
|
174
|
+
"#{@name}[]"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Checks if a specific value is currently selected.
|
|
178
|
+
#
|
|
179
|
+
# @param value [String, Integer] the value to check
|
|
180
|
+
# @return [Boolean] true if the value is selected, false otherwise
|
|
181
|
+
# @api private
|
|
182
|
+
def item_checked?(value)
|
|
183
|
+
@selected.include?(value.to_s)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Extracts the label from a collection item.
|
|
187
|
+
#
|
|
188
|
+
# @param item [String, Array] the collection item
|
|
189
|
+
# @return [String] the label text
|
|
190
|
+
# @api private
|
|
191
|
+
def item_label(item)
|
|
192
|
+
item.is_a?(Array) ? item.first.to_s : item.to_s.humanize
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# Extracts the value from a collection item.
|
|
196
|
+
#
|
|
197
|
+
# @param item [String, Array] the collection item
|
|
198
|
+
# @return [String] the value
|
|
199
|
+
# @api private
|
|
200
|
+
def item_value(item)
|
|
201
|
+
item.is_a?(Array) ? item.last.to_s : item.to_s
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# Generates a unique ID for each checkbox item.
|
|
205
|
+
#
|
|
206
|
+
# @param index [Integer] the item index
|
|
207
|
+
# @return [String] the generated ID
|
|
208
|
+
# @api private
|
|
209
|
+
def item_id(index)
|
|
210
|
+
base_id = @name.to_s.gsub(/\[|\]/, "_").gsub(/_+/, "_").chomp("_")
|
|
211
|
+
"#{base_id}_#{index}"
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Returns the CSS classes for the fieldset wrapper.
|
|
215
|
+
#
|
|
216
|
+
# @return [String] the merged CSS class string
|
|
217
|
+
# @api private
|
|
218
|
+
def wrapper_classes
|
|
219
|
+
css_classes([
|
|
220
|
+
"form-field-wrapper",
|
|
221
|
+
@container_classes
|
|
222
|
+
].flatten.compact)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Returns the CSS classes for the legend element.
|
|
226
|
+
#
|
|
227
|
+
# @return [String] the merged CSS class string for the legend
|
|
228
|
+
# @api private
|
|
229
|
+
def legend_element_classes
|
|
230
|
+
css_classes([
|
|
231
|
+
"block",
|
|
232
|
+
"font-medium",
|
|
233
|
+
"text-gray-700",
|
|
234
|
+
"mb-2",
|
|
235
|
+
legend_size_classes,
|
|
236
|
+
@legend_classes
|
|
237
|
+
].flatten.compact)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Returns size-specific CSS classes for the legend text.
|
|
241
|
+
#
|
|
242
|
+
# @return [String] the text size class for the current component size
|
|
243
|
+
# @api private
|
|
244
|
+
def legend_size_classes
|
|
245
|
+
case @size
|
|
246
|
+
when :xs then "text-xs"
|
|
247
|
+
when :sm then "text-sm"
|
|
248
|
+
when :md then "text-sm"
|
|
249
|
+
when :lg then "text-base"
|
|
250
|
+
when :xl then "text-lg"
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# Returns the CSS classes for the items container.
|
|
255
|
+
#
|
|
256
|
+
# @return [String] the merged CSS class string
|
|
257
|
+
# @api private
|
|
258
|
+
def items_wrapper_classes
|
|
259
|
+
css_classes([
|
|
260
|
+
"flex",
|
|
261
|
+
orientation_classes,
|
|
262
|
+
items_gap_classes,
|
|
263
|
+
@items_classes
|
|
264
|
+
].flatten.compact)
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# Returns CSS classes for orientation layout.
|
|
268
|
+
#
|
|
269
|
+
# @return [Array<String>] array of orientation CSS class strings
|
|
270
|
+
# @api private
|
|
271
|
+
def orientation_classes
|
|
272
|
+
case @orientation
|
|
273
|
+
when :vertical
|
|
274
|
+
[ "flex-col" ]
|
|
275
|
+
when :horizontal
|
|
276
|
+
[ "flex-row", "flex-wrap" ]
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
# Returns gap classes based on component size and orientation.
|
|
281
|
+
#
|
|
282
|
+
# @return [String] the gap class for the current component size
|
|
283
|
+
# @api private
|
|
284
|
+
def items_gap_classes
|
|
285
|
+
case @size
|
|
286
|
+
when :xs then @orientation == :horizontal ? "gap-x-4 gap-y-1.5" : "gap-1.5"
|
|
287
|
+
when :sm then @orientation == :horizontal ? "gap-x-5 gap-y-2" : "gap-2"
|
|
288
|
+
when :md then @orientation == :horizontal ? "gap-x-6 gap-y-2.5" : "gap-2.5"
|
|
289
|
+
when :lg then @orientation == :horizontal ? "gap-x-7 gap-y-3" : "gap-3"
|
|
290
|
+
when :xl then @orientation == :horizontal ? "gap-x-8 gap-y-3.5" : "gap-3.5"
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# Returns the CSS classes for the hint text element.
|
|
295
|
+
#
|
|
296
|
+
# @return [String] the merged CSS class string for the hint text
|
|
297
|
+
# @api private
|
|
298
|
+
def hint_element_classes
|
|
299
|
+
css_classes([
|
|
300
|
+
"block",
|
|
301
|
+
"text-gray-600",
|
|
302
|
+
"mt-2",
|
|
303
|
+
hint_size_classes,
|
|
304
|
+
@hint_classes
|
|
305
|
+
].flatten.compact)
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
# Returns size-specific CSS classes for the hint text.
|
|
309
|
+
#
|
|
310
|
+
# @return [String] the text size class for the current component size
|
|
311
|
+
# @api private
|
|
312
|
+
def hint_size_classes
|
|
313
|
+
case @size
|
|
314
|
+
when :xs then "text-xs"
|
|
315
|
+
when :sm then "text-xs"
|
|
316
|
+
when :md then "text-sm"
|
|
317
|
+
when :lg then "text-sm"
|
|
318
|
+
when :xl then "text-base"
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
# Returns the CSS classes for the error messages container.
|
|
323
|
+
#
|
|
324
|
+
# @return [String] the merged CSS class string for the error messages container
|
|
325
|
+
# @api private
|
|
326
|
+
def errors_element_classes
|
|
327
|
+
css_classes([
|
|
328
|
+
"text-danger-600",
|
|
329
|
+
"mt-2",
|
|
330
|
+
"space-y-0.5",
|
|
331
|
+
error_size_classes,
|
|
332
|
+
@error_classes
|
|
333
|
+
].flatten.compact)
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
# Returns size-specific CSS classes for error message text.
|
|
337
|
+
#
|
|
338
|
+
# @return [String] the text size class for the current component size
|
|
339
|
+
# @api private
|
|
340
|
+
def error_size_classes
|
|
341
|
+
case @size
|
|
342
|
+
when :xs then "text-xs"
|
|
343
|
+
when :sm then "text-xs"
|
|
344
|
+
when :md then "text-sm"
|
|
345
|
+
when :lg then "text-sm"
|
|
346
|
+
when :xl then "text-base"
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
# Returns the HTML attributes for the fieldset element.
|
|
351
|
+
#
|
|
352
|
+
# @return [Hash] hash of HTML attributes for the fieldset
|
|
353
|
+
# @api private
|
|
354
|
+
def fieldset_attributes
|
|
355
|
+
{
|
|
356
|
+
class: wrapper_classes,
|
|
357
|
+
disabled: @disabled || nil,
|
|
358
|
+
**@options
|
|
359
|
+
}.compact
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<div class="<%= wrapper_classes %>">
|
|
2
|
+
<% if @label.present? %>
|
|
3
|
+
<label for="<%= @name %>" class="<%= label_element_classes %>">
|
|
4
|
+
<%= @label %>
|
|
5
|
+
<% if @required %>
|
|
6
|
+
<span class="text-danger-600">*</span>
|
|
7
|
+
<% end %>
|
|
8
|
+
</label>
|
|
9
|
+
<% end %>
|
|
10
|
+
|
|
11
|
+
<div class="<%= input_wrapper_classes %>">
|
|
12
|
+
<% if has_prefix_icon? %>
|
|
13
|
+
<div class="<%= prefix_icon_classes %>">
|
|
14
|
+
<%= prefix_icon %>
|
|
15
|
+
</div>
|
|
16
|
+
<% end %>
|
|
17
|
+
|
|
18
|
+
<input <%= tag.attributes(input_attributes) %> />
|
|
19
|
+
|
|
20
|
+
<% if has_suffix_icon? %>
|
|
21
|
+
<div class="<%= suffix_icon_classes %>">
|
|
22
|
+
<%= suffix_icon %>
|
|
23
|
+
</div>
|
|
24
|
+
<% end %>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<% if @hint.present? %>
|
|
28
|
+
<div class="<%= hint_element_classes %>">
|
|
29
|
+
<%= @hint %>
|
|
30
|
+
</div>
|
|
31
|
+
<% end %>
|
|
32
|
+
|
|
33
|
+
<% if has_errors? %>
|
|
34
|
+
<div class="<%= errors_element_classes %>">
|
|
35
|
+
<% @errors.each do |error| %>
|
|
36
|
+
<div><%= error %></div>
|
|
37
|
+
<% end %>
|
|
38
|
+
</div>
|
|
39
|
+
<% end %>
|
|
40
|
+
</div>
|