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
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module BetterUi
|
|
4
|
-
module General
|
|
5
|
-
module Input
|
|
6
|
-
module Radio
|
|
7
|
-
class Component < ViewComponent::Base
|
|
8
|
-
# Costanti con classi Tailwind dirette
|
|
9
|
-
RADIO_THEME = {
|
|
10
|
-
default: 'border-gray-300 text-gray-800 focus:border-gray-600 focus:ring-gray-600 checked:bg-gray-800 checked:border-gray-800',
|
|
11
|
-
white: 'border-gray-300 text-gray-900 focus:border-gray-500 focus:ring-gray-500 checked:bg-white checked:border-gray-900 checked:text-gray-900',
|
|
12
|
-
red: 'border-gray-300 text-red-600 focus:border-red-500 focus:ring-red-500 checked:bg-red-600 checked:border-red-600',
|
|
13
|
-
rose: 'border-gray-300 text-rose-600 focus:border-rose-500 focus:ring-rose-500 checked:bg-rose-600 checked:border-rose-600',
|
|
14
|
-
orange: 'border-gray-300 text-orange-600 focus:border-orange-500 focus:ring-orange-500 checked:bg-orange-600 checked:border-orange-600',
|
|
15
|
-
green: 'border-gray-300 text-green-600 focus:border-green-500 focus:ring-green-500 checked:bg-green-600 checked:border-green-600',
|
|
16
|
-
blue: 'border-gray-300 text-blue-600 focus:border-blue-500 focus:ring-blue-500 checked:bg-blue-600 checked:border-blue-600',
|
|
17
|
-
yellow: 'border-gray-300 text-yellow-600 focus:border-yellow-500 focus:ring-yellow-500 checked:bg-yellow-600 checked:border-yellow-600',
|
|
18
|
-
violet: 'border-gray-300 text-violet-600 focus:border-violet-500 focus:ring-violet-500 checked:bg-violet-600 checked:border-violet-600'
|
|
19
|
-
}.freeze
|
|
20
|
-
|
|
21
|
-
RADIO_SIZE = {
|
|
22
|
-
small: 'h-2.5 w-2.5',
|
|
23
|
-
medium: 'h-3 w-3',
|
|
24
|
-
large: 'h-4 w-4'
|
|
25
|
-
}.freeze
|
|
26
|
-
|
|
27
|
-
RADIO_ROUNDED = {
|
|
28
|
-
none: 'rounded-none',
|
|
29
|
-
small: 'rounded-sm',
|
|
30
|
-
medium: 'rounded',
|
|
31
|
-
large: 'rounded-lg',
|
|
32
|
-
full: 'rounded-full'
|
|
33
|
-
}.freeze
|
|
34
|
-
|
|
35
|
-
RADIO_BASE_CLASSES = 'appearance-none border-2 focus:outline-none focus:ring-2 focus:ring-offset-2 transition-colors duration-200 cursor-pointer disabled:cursor-not-allowed disabled:opacity-50'.freeze
|
|
36
|
-
|
|
37
|
-
RADIO_LABEL_GAP = {
|
|
38
|
-
small: 'gap-1.5',
|
|
39
|
-
medium: 'gap-2',
|
|
40
|
-
large: 'gap-2.5'
|
|
41
|
-
}.freeze
|
|
42
|
-
|
|
43
|
-
RADIO_LABEL_TEXT = {
|
|
44
|
-
small: 'text-xs',
|
|
45
|
-
medium: 'text-sm',
|
|
46
|
-
large: 'text-base'
|
|
47
|
-
}.freeze
|
|
48
|
-
|
|
49
|
-
attr_reader :name, :value, :checked, :required, :disabled,
|
|
50
|
-
:label, :label_position, :theme, :size, :rounded, :classes, :form, :options
|
|
51
|
-
|
|
52
|
-
# @param name [String] Nome del campo radio (obbligatorio)
|
|
53
|
-
# @param value [String] Valore del radio button (obbligatorio)
|
|
54
|
-
# @param checked [Boolean] Se il radio è selezionato
|
|
55
|
-
# @param required [Boolean] Se il campo è obbligatorio
|
|
56
|
-
# @param disabled [Boolean] Se il campo è disabilitato
|
|
57
|
-
# @param label [String, nil] Testo della label associata al radio
|
|
58
|
-
# @param label_position [Symbol] Posizione della label (:left, :right)
|
|
59
|
-
# @param theme [Symbol] Tema del componente (:default, :white, :red, :rose, :orange, :green, :blue, :yellow, :violet)
|
|
60
|
-
# @param size [Symbol] Dimensione del componente (:small, :medium, :large)
|
|
61
|
-
# @param rounded [Symbol] Border radius (:none, :small, :medium, :large, :full)
|
|
62
|
-
# @param classes [String] Classi CSS aggiuntive
|
|
63
|
-
# @param form [ActionView::Helpers::FormBuilder, nil] Form builder Rails opzionale
|
|
64
|
-
# @param options [Hash] Opzioni aggiuntive per l'input (es. data attributes, aria attributes)
|
|
65
|
-
def initialize(name:, value:, checked: false, required: false, disabled: false,
|
|
66
|
-
label: nil, label_position: :right, theme: :default,
|
|
67
|
-
size: :medium, rounded: :full, classes: '', form: nil, **options)
|
|
68
|
-
@name = name
|
|
69
|
-
@value = value
|
|
70
|
-
@checked = checked
|
|
71
|
-
@required = required
|
|
72
|
-
@disabled = disabled
|
|
73
|
-
@label = label
|
|
74
|
-
@label_position = label_position.to_sym
|
|
75
|
-
@theme = theme.to_sym
|
|
76
|
-
@size = size.to_sym
|
|
77
|
-
@rounded = rounded.to_sym
|
|
78
|
-
@classes = classes
|
|
79
|
-
@form = form
|
|
80
|
-
@options = options
|
|
81
|
-
|
|
82
|
-
validate_params
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
private
|
|
86
|
-
|
|
87
|
-
def validate_params
|
|
88
|
-
validate_theme
|
|
89
|
-
validate_size
|
|
90
|
-
validate_rounded
|
|
91
|
-
validate_label_position
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def validate_theme
|
|
95
|
-
return if RADIO_THEME.key?(@theme)
|
|
96
|
-
|
|
97
|
-
raise ArgumentError, "Invalid theme: #{@theme}. Valid themes are: #{RADIO_THEME.keys.join(', ')}"
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def validate_size
|
|
101
|
-
return if RADIO_SIZE.key?(@size)
|
|
102
|
-
|
|
103
|
-
raise ArgumentError, "Invalid size: #{@size}. Valid sizes are: #{RADIO_SIZE.keys.join(', ')}"
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def validate_rounded
|
|
107
|
-
return if RADIO_ROUNDED.key?(@rounded)
|
|
108
|
-
|
|
109
|
-
raise ArgumentError, "Invalid rounded: #{@rounded}. Valid rounded options are: #{RADIO_ROUNDED.keys.join(', ')}"
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
def validate_label_position
|
|
113
|
-
return if [:left, :right].include?(@label_position)
|
|
114
|
-
|
|
115
|
-
raise ArgumentError, "Invalid label_position: #{@label_position}. Valid positions are: left, right"
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
def radio_classes
|
|
119
|
-
[
|
|
120
|
-
RADIO_BASE_CLASSES,
|
|
121
|
-
RADIO_THEME[@theme],
|
|
122
|
-
RADIO_SIZE[@size],
|
|
123
|
-
RADIO_ROUNDED[@rounded],
|
|
124
|
-
@classes
|
|
125
|
-
].compact.join(' ')
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
def input_attributes
|
|
129
|
-
attrs = {
|
|
130
|
-
type: 'radio',
|
|
131
|
-
name: input_name,
|
|
132
|
-
value: @value,
|
|
133
|
-
class: radio_classes,
|
|
134
|
-
checked: @checked,
|
|
135
|
-
required: @required,
|
|
136
|
-
disabled: @disabled,
|
|
137
|
-
id: input_id
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
# Unisci le opzioni personalizzate
|
|
141
|
-
attrs.merge(@options)
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def input_name
|
|
145
|
-
if @form
|
|
146
|
-
@form.field_name(@name)
|
|
147
|
-
else
|
|
148
|
-
@name
|
|
149
|
-
end
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def input_id
|
|
153
|
-
@options[:id] || "radio_#{@name}_#{@value}"
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
def label_classes
|
|
157
|
-
[
|
|
158
|
-
'flex items-center cursor-pointer',
|
|
159
|
-
@disabled ? 'opacity-50 cursor-not-allowed' : '',
|
|
160
|
-
RADIO_LABEL_GAP[@size]
|
|
161
|
-
].compact.join(' ')
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
def label_text_classes
|
|
165
|
-
RADIO_LABEL_TEXT[@size]
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
def input_tag
|
|
169
|
-
if @form
|
|
170
|
-
form_radio
|
|
171
|
-
else
|
|
172
|
-
manual_input
|
|
173
|
-
end
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
def form_radio
|
|
177
|
-
@form.radio_button(@name, @value, {
|
|
178
|
-
class: radio_classes,
|
|
179
|
-
id: input_id,
|
|
180
|
-
checked: @checked,
|
|
181
|
-
disabled: @disabled,
|
|
182
|
-
required: @required,
|
|
183
|
-
**@options
|
|
184
|
-
})
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
def manual_input
|
|
188
|
-
attrs = input_attributes.map do |key, value|
|
|
189
|
-
if value == true
|
|
190
|
-
key.to_s
|
|
191
|
-
elsif value == false || value.nil?
|
|
192
|
-
nil
|
|
193
|
-
else
|
|
194
|
-
"#{key}=\"#{value}\""
|
|
195
|
-
end
|
|
196
|
-
end.compact.join(' ')
|
|
197
|
-
|
|
198
|
-
"<input #{attrs} />".html_safe
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
def render_radio_with_label
|
|
202
|
-
if @label_position == :left
|
|
203
|
-
label_left_content
|
|
204
|
-
else
|
|
205
|
-
label_right_content
|
|
206
|
-
end
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
def label_left_content
|
|
210
|
-
content_tag(:label, class: label_classes, for: input_id) do
|
|
211
|
-
safe_join([
|
|
212
|
-
content_tag(:span, @label, class: label_text_classes),
|
|
213
|
-
input_tag
|
|
214
|
-
])
|
|
215
|
-
end
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
def label_right_content
|
|
219
|
-
content_tag(:label, class: label_classes, for: input_id) do
|
|
220
|
-
safe_join([
|
|
221
|
-
input_tag,
|
|
222
|
-
content_tag(:span, @label, class: label_text_classes)
|
|
223
|
-
])
|
|
224
|
-
end
|
|
225
|
-
end
|
|
226
|
-
end
|
|
227
|
-
end
|
|
228
|
-
end
|
|
229
|
-
end
|
|
230
|
-
end
|
|
@@ -1,272 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module BetterUi
|
|
4
|
-
module General
|
|
5
|
-
module Input
|
|
6
|
-
module Rating
|
|
7
|
-
class Component < ViewComponent::Base
|
|
8
|
-
# Costanti con classi Tailwind dirette
|
|
9
|
-
RATING_THEME = {
|
|
10
|
-
default: 'text-yellow-400',
|
|
11
|
-
yellow: 'text-yellow-400',
|
|
12
|
-
orange: 'text-orange-400',
|
|
13
|
-
red: 'text-red-400',
|
|
14
|
-
pink: 'text-pink-400',
|
|
15
|
-
purple: 'text-purple-400',
|
|
16
|
-
blue: 'text-blue-400',
|
|
17
|
-
green: 'text-green-400',
|
|
18
|
-
gray: 'text-gray-400'
|
|
19
|
-
}.freeze
|
|
20
|
-
|
|
21
|
-
RATING_SIZE = {
|
|
22
|
-
small: 'text-sm',
|
|
23
|
-
medium: 'text-xl',
|
|
24
|
-
large: 'text-3xl'
|
|
25
|
-
}.freeze
|
|
26
|
-
|
|
27
|
-
RATING_EMPTY_COLOR = 'text-gray-300'.freeze
|
|
28
|
-
RATING_HALF_COLOR = 'text-yellow-300'.freeze
|
|
29
|
-
|
|
30
|
-
attr_reader :name, :value, :max_stars, :readonly, :half_stars,
|
|
31
|
-
:theme, :size, :show_value, :form, :classes, :options
|
|
32
|
-
|
|
33
|
-
# @param name [String] Nome del campo rating (obbligatorio se non readonly)
|
|
34
|
-
# @param value [Float, Integer] Valore del rating attuale (0.0 - max_stars)
|
|
35
|
-
# @param max_stars [Integer] Numero massimo di stelle (default: 5)
|
|
36
|
-
# @param readonly [Boolean] Se il rating è in sola lettura
|
|
37
|
-
# @param half_stars [Boolean] Se supportare mezze stelle
|
|
38
|
-
# @param theme [Symbol] Tema del componente (:default, :yellow, :orange, :red, :pink, :purple, :blue, :green, :gray)
|
|
39
|
-
# @param size [Symbol] Dimensione del componente (:small, :medium, :large)
|
|
40
|
-
# @param show_value [Boolean] Se mostrare il valore numerico accanto alle stelle
|
|
41
|
-
# @param form [ActionView::Helpers::FormBuilder, nil] Form builder Rails opzionale
|
|
42
|
-
# @param classes [String] Classi CSS aggiuntive
|
|
43
|
-
# @param options [Hash] Opzioni aggiuntive per attributi HTML
|
|
44
|
-
def initialize(name: nil, value: 0, max_stars: 5, readonly: false, half_stars: true,
|
|
45
|
-
theme: :default, size: :medium, show_value: false, form: nil,
|
|
46
|
-
classes: '', **options)
|
|
47
|
-
@name = name
|
|
48
|
-
@value = value.to_f
|
|
49
|
-
@max_stars = max_stars.to_i
|
|
50
|
-
@readonly = readonly
|
|
51
|
-
@half_stars = half_stars
|
|
52
|
-
@theme = theme.to_sym
|
|
53
|
-
@size = size.to_sym
|
|
54
|
-
@show_value = show_value
|
|
55
|
-
@form = form
|
|
56
|
-
@classes = classes
|
|
57
|
-
@options = options
|
|
58
|
-
|
|
59
|
-
validate_params
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
private
|
|
63
|
-
|
|
64
|
-
def validate_params
|
|
65
|
-
validate_theme
|
|
66
|
-
validate_size
|
|
67
|
-
validate_value
|
|
68
|
-
validate_max_stars
|
|
69
|
-
validate_name if interactive?
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def validate_theme
|
|
73
|
-
return if RATING_THEME.key?(@theme)
|
|
74
|
-
|
|
75
|
-
raise ArgumentError, "Invalid theme: #{@theme}. Valid themes are: #{RATING_THEME.keys.join(', ')}"
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def validate_size
|
|
79
|
-
return if RATING_SIZE.key?(@size)
|
|
80
|
-
|
|
81
|
-
raise ArgumentError, "Invalid size: #{@size}. Valid sizes are: #{RATING_SIZE.keys.join(', ')}"
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def validate_value
|
|
85
|
-
return if @value >= 0 && @value <= @max_stars
|
|
86
|
-
|
|
87
|
-
raise ArgumentError, "Value must be between 0 and #{@max_stars}, got: #{@value}"
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def validate_max_stars
|
|
91
|
-
return if @max_stars > 0
|
|
92
|
-
|
|
93
|
-
raise ArgumentError, "Max stars must be greater than 0, got: #{@max_stars}"
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def validate_name
|
|
97
|
-
return if @name.present?
|
|
98
|
-
|
|
99
|
-
raise ArgumentError, "Name is required for interactive rating components"
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def interactive?
|
|
103
|
-
!@readonly
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def container_classes
|
|
107
|
-
base_classes = ['inline-flex', 'items-center', 'gap-1']
|
|
108
|
-
base_classes << @classes if @classes.present?
|
|
109
|
-
base_classes.join(' ')
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
def rating_container_classes
|
|
113
|
-
base_classes = ['flex', 'items-center']
|
|
114
|
-
base_classes << (interactive? ? 'cursor-pointer' : 'cursor-default')
|
|
115
|
-
base_classes.join(' ')
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
def star_classes(index)
|
|
119
|
-
base_classes = [RATING_SIZE[@size], 'transition-colors', 'duration-150']
|
|
120
|
-
base_classes << (interactive? ? 'hover:scale-110 transform transition-transform' : '')
|
|
121
|
-
base_classes.compact.join(' ')
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def controller_attributes
|
|
125
|
-
return {} unless interactive?
|
|
126
|
-
|
|
127
|
-
{
|
|
128
|
-
data: {
|
|
129
|
-
controller: 'bui-rating',
|
|
130
|
-
'bui-rating-rating-value': @value,
|
|
131
|
-
'bui-rating-max-value': @max_stars,
|
|
132
|
-
'bui-rating-readonly-value': @readonly,
|
|
133
|
-
'bui-rating-half-stars-value': @half_stars,
|
|
134
|
-
'bui-rating-name-value': @name,
|
|
135
|
-
action: 'keydown->bui-rating#keydown'
|
|
136
|
-
},
|
|
137
|
-
tabindex: '0'
|
|
138
|
-
}
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
def star_attributes(index)
|
|
142
|
-
attrs = {
|
|
143
|
-
data: {
|
|
144
|
-
'bui-rating-target': 'star',
|
|
145
|
-
index: index
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if interactive?
|
|
150
|
-
attrs[:data][:action] = [
|
|
151
|
-
'click->bui-rating#starClick',
|
|
152
|
-
'mouseover->bui-rating#starHover',
|
|
153
|
-
'mouseleave->bui-rating#starLeave'
|
|
154
|
-
].join(' ')
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
attrs
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
def hidden_input_attributes
|
|
161
|
-
return {} unless interactive?
|
|
162
|
-
|
|
163
|
-
{
|
|
164
|
-
type: 'hidden',
|
|
165
|
-
name: input_name,
|
|
166
|
-
value: @value,
|
|
167
|
-
data: { 'bui-rating-target': 'hiddenInput' }
|
|
168
|
-
}
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
def input_name
|
|
172
|
-
if @form
|
|
173
|
-
@form.field_name(@name)
|
|
174
|
-
else
|
|
175
|
-
@name
|
|
176
|
-
end
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
def input_id
|
|
180
|
-
@options[:id] || "rating_#{@name}"
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
def display_value
|
|
184
|
-
if @value % 1 == 0
|
|
185
|
-
@value.to_i.to_s
|
|
186
|
-
else
|
|
187
|
-
@value.to_s
|
|
188
|
-
end
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
def star_display_state(index)
|
|
192
|
-
star_number = index + 1
|
|
193
|
-
|
|
194
|
-
if @value >= star_number
|
|
195
|
-
:full
|
|
196
|
-
elsif @half_stars && @value >= star_number - 0.5
|
|
197
|
-
:half
|
|
198
|
-
else
|
|
199
|
-
:empty
|
|
200
|
-
end
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
def star_color(state)
|
|
204
|
-
case state
|
|
205
|
-
when :full
|
|
206
|
-
RATING_THEME[@theme]
|
|
207
|
-
when :half
|
|
208
|
-
RATING_HALF_COLOR
|
|
209
|
-
when :empty
|
|
210
|
-
RATING_EMPTY_COLOR
|
|
211
|
-
end
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
def star_symbol(state)
|
|
215
|
-
case state
|
|
216
|
-
when :full, :half
|
|
217
|
-
'★'
|
|
218
|
-
when :empty
|
|
219
|
-
'☆'
|
|
220
|
-
end
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
def render_star(index)
|
|
224
|
-
state = star_display_state(index)
|
|
225
|
-
|
|
226
|
-
content_tag(:span, star_attributes(index).merge(class: "#{star_classes(index)} #{star_color(state)}")) do
|
|
227
|
-
if state == :half
|
|
228
|
-
render_half_star
|
|
229
|
-
else
|
|
230
|
-
star_symbol(state)
|
|
231
|
-
end
|
|
232
|
-
end
|
|
233
|
-
end
|
|
234
|
-
|
|
235
|
-
def render_half_star
|
|
236
|
-
content_tag(:span, class: 'relative inline-block') do
|
|
237
|
-
safe_join([
|
|
238
|
-
content_tag(:span, '☆', class: RATING_EMPTY_COLOR),
|
|
239
|
-
content_tag(:span, class: 'absolute inset-0 overflow-hidden w-1/2') do
|
|
240
|
-
content_tag(:span, '★', class: RATING_THEME[@theme])
|
|
241
|
-
end
|
|
242
|
-
])
|
|
243
|
-
end
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
def render_hidden_input
|
|
247
|
-
return unless interactive?
|
|
248
|
-
|
|
249
|
-
tag(:input, hidden_input_attributes)
|
|
250
|
-
end
|
|
251
|
-
|
|
252
|
-
def render_value_display
|
|
253
|
-
return unless @show_value
|
|
254
|
-
|
|
255
|
-
content_tag(:span, class: "ml-2 text-sm text-gray-600", data: { 'bui-rating-target': 'display' }) do
|
|
256
|
-
"(#{display_value})"
|
|
257
|
-
end
|
|
258
|
-
end
|
|
259
|
-
|
|
260
|
-
def render_stars_container
|
|
261
|
-
content_tag(:div, class: rating_container_classes, **controller_attributes) do
|
|
262
|
-
safe_join([
|
|
263
|
-
render_hidden_input,
|
|
264
|
-
*@max_stars.times.map { |i| render_star(i) }
|
|
265
|
-
].compact)
|
|
266
|
-
end
|
|
267
|
-
end
|
|
268
|
-
end
|
|
269
|
-
end
|
|
270
|
-
end
|
|
271
|
-
end
|
|
272
|
-
end
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
<%= tag.div(**container_attributes) do %>
|
|
2
|
-
<!-- Hidden input for form compatibility -->
|
|
3
|
-
<input
|
|
4
|
-
type="hidden"
|
|
5
|
-
name="<%= input_name %>"
|
|
6
|
-
id="<%= input_id %>"
|
|
7
|
-
value="<%= hidden_input_value %>"
|
|
8
|
-
data-select-target="hiddenInput"
|
|
9
|
-
<%= "required" if @required %>
|
|
10
|
-
<%= "disabled" if @disabled %>
|
|
11
|
-
/>
|
|
12
|
-
|
|
13
|
-
<!-- Trigger button -->
|
|
14
|
-
<button
|
|
15
|
-
type="button"
|
|
16
|
-
class="<%= trigger_classes %>"
|
|
17
|
-
data-select-target="trigger"
|
|
18
|
-
data-action="click->select#toggle"
|
|
19
|
-
<%= "disabled" if @disabled %>
|
|
20
|
-
>
|
|
21
|
-
<span data-select-text class="<%= trigger_text_classes %>">
|
|
22
|
-
<%= trigger_text %>
|
|
23
|
-
</span>
|
|
24
|
-
<%= chevron_icon %>
|
|
25
|
-
</button>
|
|
26
|
-
|
|
27
|
-
<!-- Badge container for multi-select -->
|
|
28
|
-
<% if @multiple %>
|
|
29
|
-
<div
|
|
30
|
-
class="<%= badge_container_classes %>"
|
|
31
|
-
data-select-target="badgeContainer"
|
|
32
|
-
style="<%= @selected.empty? ? 'display: none;' : '' %>"
|
|
33
|
-
>
|
|
34
|
-
<!-- Badges will be populated by Stimulus -->
|
|
35
|
-
</div>
|
|
36
|
-
<% end %>
|
|
37
|
-
|
|
38
|
-
<!-- Dropdown panel -->
|
|
39
|
-
<div class="<%= dropdown_classes %>" data-select-target="dropdown">
|
|
40
|
-
<!-- Search input -->
|
|
41
|
-
<% if @searchable %>
|
|
42
|
-
<div class="p-1">
|
|
43
|
-
<input
|
|
44
|
-
type="text"
|
|
45
|
-
placeholder="<%= @search_placeholder %>"
|
|
46
|
-
class="<%= search_input_classes %>"
|
|
47
|
-
data-select-target="search"
|
|
48
|
-
data-action="input->select#search"
|
|
49
|
-
/>
|
|
50
|
-
</div>
|
|
51
|
-
<% end %>
|
|
52
|
-
|
|
53
|
-
<!-- Options container -->
|
|
54
|
-
<div class="<%= options_container_classes %>">
|
|
55
|
-
<% @options.each do |option| %>
|
|
56
|
-
<div
|
|
57
|
-
class="<%= option_classes %> <%= 'bg-gray-100' if option_selected?(option) %>"
|
|
58
|
-
data-select-target="option"
|
|
59
|
-
data-value="<%= option[:value] %>"
|
|
60
|
-
data-action="click->select#selectOption"
|
|
61
|
-
<%= "data-disabled" if option[:disabled] %>
|
|
62
|
-
>
|
|
63
|
-
<span><%= option[:label] %></span>
|
|
64
|
-
<% if option_selected?(option) %>
|
|
65
|
-
<span class="checkmark text-gray-600">✓</span>
|
|
66
|
-
<% end %>
|
|
67
|
-
</div>
|
|
68
|
-
<% end %>
|
|
69
|
-
</div>
|
|
70
|
-
|
|
71
|
-
<!-- Empty state -->
|
|
72
|
-
<% if @options.empty? %>
|
|
73
|
-
<div class="px-3 py-6 text-center text-gray-500 text-sm">
|
|
74
|
-
Nessuna opzione disponibile
|
|
75
|
-
</div>
|
|
76
|
-
<% end %>
|
|
77
|
-
</div>
|
|
78
|
-
<% end %>
|