better_ui 0.2.0 → 0.6.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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/app/components/better_ui/application/main/component.html.erb +1 -1
  3. data/app/components/better_ui/application/sidebar/component.html.erb +77 -18
  4. data/app/components/better_ui/application/sidebar/component.rb +63 -5
  5. data/app/components/better_ui/general/accordion/component.html.erb +5 -0
  6. data/app/components/better_ui/general/accordion/component.rb +92 -0
  7. data/app/components/better_ui/general/accordion/item_component.html.erb +12 -0
  8. data/app/components/better_ui/general/accordion/item_component.rb +176 -0
  9. data/app/components/better_ui/general/button/component.html.erb +8 -8
  10. data/app/components/better_ui/general/button/component.rb +11 -11
  11. data/app/components/better_ui/general/dropdown/component.html.erb +21 -7
  12. data/app/components/better_ui/general/dropdown/component.rb +27 -54
  13. data/app/components/better_ui/general/dropdown/item_component.rb +2 -1
  14. data/app/components/better_ui/general/field/component.html.erb +3 -3
  15. data/app/components/better_ui/general/field/component.rb +3 -3
  16. data/app/components/better_ui/general/grid/cell_component.html.erb +3 -0
  17. data/app/components/better_ui/general/grid/cell_component.rb +390 -0
  18. data/app/components/better_ui/general/grid/component.html.erb +3 -0
  19. data/app/components/better_ui/general/grid/component.rb +301 -0
  20. data/app/components/better_ui/general/heading/component.html.erb +1 -1
  21. data/app/components/better_ui/general/icon/component.rb +2 -1
  22. data/app/components/better_ui/general/input/checkbox/component.rb +10 -10
  23. data/app/components/better_ui/general/input/pin/component.html.erb +1 -0
  24. data/app/components/better_ui/general/input/pin/component.rb +201 -0
  25. data/app/components/better_ui/general/input/radio/component.rb +10 -10
  26. data/app/components/better_ui/general/input/rating/component.html.erb +4 -0
  27. data/app/components/better_ui/general/input/rating/component.rb +272 -0
  28. data/app/components/better_ui/general/input/select/component.html.erb +76 -14
  29. data/app/components/better_ui/general/input/select/component.rb +166 -101
  30. data/app/components/better_ui/general/input/toggle/component.html.erb +5 -0
  31. data/app/components/better_ui/general/input/toggle/component.rb +242 -0
  32. data/app/components/better_ui/general/link/component.rb +1 -1
  33. data/app/components/better_ui/general/modal/component.html.erb +5 -42
  34. data/app/components/better_ui/general/modal/component.rb +22 -140
  35. data/app/components/better_ui/general/modal/modal_component.html.erb +52 -0
  36. data/app/components/better_ui/general/modal/modal_component.rb +160 -0
  37. data/app/components/better_ui/general/tabs/component.html.erb +10 -2
  38. data/app/components/better_ui/general/tabs/component.rb +26 -8
  39. data/app/components/better_ui/general/tabs/panel_component.rb +1 -1
  40. data/app/components/better_ui/general/tabs/tab_component.rb +1 -1
  41. data/app/components/better_ui/general/text/component.html.erb +1 -0
  42. data/app/components/better_ui/general/text/component.rb +194 -0
  43. data/app/helpers/better_ui/application_helper.rb +11 -4
  44. data/app/helpers/better_ui/general/components/accordion/accordion_helper.rb +73 -0
  45. data/app/helpers/better_ui/general/components/button/button_helper.rb +6 -6
  46. data/app/helpers/better_ui/general/components/dropdown/dropdown_helper.rb +9 -0
  47. data/app/helpers/better_ui/general/components/dropdown/item_helper.rb +13 -7
  48. data/app/helpers/better_ui/general/components/field/field_helper.rb +4 -4
  49. data/app/helpers/better_ui/general/components/grid/grid_helper.rb +145 -0
  50. data/app/helpers/better_ui/general/components/input/pin/pin_helper.rb +76 -0
  51. data/app/helpers/better_ui/general/components/input/rating/rating_helper.rb +70 -0
  52. data/app/helpers/better_ui/general/components/input/select/select_helper.rb +47 -31
  53. data/app/helpers/better_ui/general/components/input/toggle/toggle_helper.rb +77 -0
  54. data/app/helpers/better_ui/general/components/modal/modal_helper.rb +34 -44
  55. data/app/helpers/better_ui/general/components/tabs/tabs_helper.rb +59 -26
  56. data/app/helpers/better_ui/general/components/text/text_helper.rb +83 -0
  57. data/lib/better_ui/version.rb +1 -1
  58. data/lib/better_ui.rb +1 -0
  59. metadata +26 -2
@@ -2,163 +2,45 @@ module BetterUi
2
2
  module General
3
3
  module Modal
4
4
  class Component < ViewComponent::Base
5
- attr_reader :title, :theme, :size, :backdrop, :closable, :classes, :html_options
5
+ renders_one :trigger
6
+ renders_one :modal
7
+
8
+ attr_reader :close_on_backdrop, :close_on_escape, :lock_scroll, :classes, :html_options
6
9
 
7
- # Classi base sempre presenti per il backdrop
8
- MODAL_BACKDROP_CLASSES = "fixed inset-0 z-50 flex items-center justify-center p-4 bg-black bg-opacity-50"
9
10
 
10
- # Classi base per il contenitore del modal
11
- MODAL_CONTAINER_CLASSES = "relative bg-white shadow-xl w-full"
12
11
 
13
- # Temi dell'header del modal con classi Tailwind dirette
14
- MODAL_THEME = {
15
- default: "bg-gray-50 border-b border-gray-200 text-gray-900",
16
- white: "bg-white border-b border-gray-200 text-gray-900",
17
- red: "bg-red-50 border-b border-red-200 text-red-900",
18
- rose: "bg-rose-50 border-b border-rose-200 text-rose-900",
19
- orange: "bg-orange-50 border-b border-orange-200 text-orange-900",
20
- green: "bg-green-50 border-b border-green-200 text-green-900",
21
- blue: "bg-blue-50 border-b border-blue-200 text-blue-900",
22
- yellow: "bg-yellow-50 border-b border-yellow-200 text-yellow-900",
23
- violet: "bg-violet-50 border-b border-violet-200 text-violet-900"
24
- }
25
-
26
- # Dimensioni con classi Tailwind dirette
27
- MODAL_SIZES = {
28
- small: "max-w-sm",
29
- medium: "max-w-md",
30
- large: "max-w-2xl"
31
- }
32
-
33
- # Border radius con classi Tailwind dirette
34
- MODAL_ROUNDED = {
35
- none: "rounded-none",
36
- small: "rounded-md",
37
- medium: "rounded-lg",
38
- large: "rounded-xl",
39
- full: "rounded-full"
40
- }
41
-
42
- # Inizializzazione del componente
12
+ # Inizializzazione del wrapper component
43
13
  def initialize(
44
- title:,
45
- theme: :default,
46
- size: :medium,
47
- rounded: :medium,
48
- backdrop: true,
49
- closable: true,
14
+ close_on_backdrop: true,
15
+ close_on_escape: true,
16
+ lock_scroll: true,
50
17
  classes: nil,
51
18
  **html_options
52
19
  )
53
- @title = title
54
- @theme = theme.to_sym
55
- @size = size.to_sym
56
- @rounded = rounded.to_sym
57
- @backdrop = backdrop
58
- @closable = closable
20
+ @close_on_backdrop = close_on_backdrop
21
+ @close_on_escape = close_on_escape
22
+ @lock_scroll = lock_scroll
59
23
  @classes = classes
60
24
  @html_options = html_options
61
-
62
- validate_params
63
- end
64
-
65
- # Combina tutte le classi per il backdrop
66
- def backdrop_classes
67
- MODAL_BACKDROP_CLASSES
68
- end
69
-
70
- # Combina tutte le classi per il contenitore
71
- def container_classes
72
- [
73
- MODAL_CONTAINER_CLASSES,
74
- get_modal_size_classes,
75
- get_modal_rounded_classes,
76
- @classes,
77
- @html_options[:class]
78
- ].compact.join(" ")
79
- end
80
-
81
- # Combina tutte le classi per l'header
82
- def header_classes
83
- [
84
- "flex items-center justify-between p-6",
85
- get_modal_theme_classes
86
- ].compact.join(" ")
87
- end
88
-
89
- def get_modal_theme_classes
90
- MODAL_THEME[@theme] || MODAL_THEME[:default]
91
- end
92
-
93
- def get_modal_size_classes
94
- MODAL_SIZES[@size] || MODAL_SIZES[:medium]
95
- end
96
-
97
- def get_modal_rounded_classes
98
- MODAL_ROUNDED[@rounded] || MODAL_ROUNDED[:medium]
99
- end
100
-
101
- # Restituisce gli attributi per il backdrop
102
- def backdrop_attributes
103
- attrs = {
104
- class: backdrop_classes
105
- }
106
-
107
- # Aggiungi altri attributi HTML se presenti
108
- @html_options.except(:class).each do |key, value|
109
- attrs[key] = value
110
- end
111
-
112
- attrs
113
25
  end
114
26
 
115
- # Restituisce gli attributi per il contenitore
116
- def container_attributes
117
- {
118
- class: container_classes,
119
- role: "dialog",
120
- "aria-modal": "true",
121
- "aria-labelledby": "modal-title"
122
- }
27
+ # Combina tutte le classi per il wrapper
28
+ def wrapper_classes
29
+ [@classes, @html_options[:class]].compact.join(" ")
123
30
  end
124
31
 
125
- # Restituisce gli attributi per l'header
126
- def header_attributes
32
+ # Restituisce gli attributi per il wrapper principale (con controller Stimulus)
33
+ def wrapper_attributes
127
34
  {
128
- class: header_classes
129
- }
130
- end
131
-
132
- # Verifica se rendere il componente
133
- def render?
134
- @title.present?
35
+ class: wrapper_classes,
36
+ 'data-controller': 'bui-modal',
37
+ 'data-bui-modal-close-on-backdrop-value': close_on_backdrop,
38
+ 'data-bui-modal-close-on-escape-value': close_on_escape,
39
+ 'data-bui-modal-lock-scroll-value': lock_scroll
40
+ }.merge(@html_options.except(:class))
135
41
  end
136
42
 
137
- private
138
43
 
139
- def validate_params
140
- validate_theme
141
- validate_size
142
- validate_rounded
143
- end
144
-
145
- def validate_theme
146
- unless MODAL_THEME.keys.include?(@theme)
147
- raise ArgumentError, "Il tema deve essere uno tra: #{MODAL_THEME.keys.join(', ')}"
148
- end
149
- end
150
-
151
- def validate_size
152
- unless MODAL_SIZES.keys.include?(@size)
153
- raise ArgumentError, "La dimensione deve essere una tra: #{MODAL_SIZES.keys.join(', ')}"
154
- end
155
- end
156
-
157
- def validate_rounded
158
- unless MODAL_ROUNDED.keys.include?(@rounded)
159
- raise ArgumentError, "Il border radius deve essere uno tra: #{MODAL_ROUNDED.keys.join(', ')}"
160
- end
161
- end
162
44
  end
163
45
  end
164
46
  end
@@ -0,0 +1,52 @@
1
+ <%# Template per il modal content %>
2
+ <% if @backdrop %>
3
+ <%= tag.div **backdrop_attributes do %>
4
+ <%= tag.div **container_attributes do %>
5
+ <%# Header del modal %>
6
+ <%= tag.div **header_attributes do %>
7
+ <h3 class="text-lg font-semibold" id="modal-title"><%= @title %></h3>
8
+ <% if @closable %>
9
+ <%= helpers.bui_button(
10
+ label: "Chiudi",
11
+ icon: "x-mark",
12
+ type: :white,
13
+ size: :small,
14
+ data: [
15
+ { name: 'bui-modal-target', value: 'closeButton' },
16
+ { name: 'action', value: 'click->bui-modal#closeButtonClicked' }
17
+ ]
18
+ ) %>
19
+ <% end %>
20
+ <% end %>
21
+
22
+ <%# Body del modal %>
23
+ <div class="p-6">
24
+ <%= content %>
25
+ </div>
26
+ <% end %>
27
+ <% end %>
28
+ <% else %>
29
+ <%= tag.div **container_attributes do %>
30
+ <%# Header del modal %>
31
+ <%= tag.div **header_attributes do %>
32
+ <h3 class="text-lg font-semibold" id="modal-title"><%= @title %></h3>
33
+ <% if @closable %>
34
+ <%= helpers.bui_button(
35
+ label: "Chiudi",
36
+ icon: "x-mark",
37
+ type: :white,
38
+ size: :small,
39
+ data: [
40
+ { name: 'bui-modal-target', value: 'closeButton' },
41
+ { name: 'action', value: 'click->bui-modal#closeButtonClicked' }
42
+ ]
43
+ ) %>
44
+ <% end %>
45
+ <% end %>
46
+
47
+ <%# Body del modal %>
48
+ <div class="p-6">
49
+ <%= content %>
50
+ </div>
51
+ <% end %>
52
+ <% end %>
@@ -0,0 +1,160 @@
1
+ module BetterUi
2
+ module General
3
+ module Modal
4
+ class ModalComponent < ViewComponent::Base
5
+ attr_reader :title, :theme, :size, :backdrop, :closable, :classes, :html_options
6
+
7
+ # Classi base sempre presenti per il backdrop
8
+ MODAL_BACKDROP_CLASSES = "fixed inset-0 z-50 flex items-center justify-center p-4 bg-black bg-opacity-50"
9
+
10
+ # Classi base per il contenitore del modal
11
+ MODAL_CONTAINER_CLASSES = "relative bg-white shadow-xl w-full"
12
+
13
+ # Temi dell'header del modal con classi Tailwind dirette
14
+ MODAL_THEME = {
15
+ default: "bg-gray-50 border-b border-gray-200 text-gray-900",
16
+ white: "bg-white border-b border-gray-200 text-gray-900",
17
+ red: "bg-red-50 border-b border-red-200 text-red-900",
18
+ rose: "bg-rose-50 border-b border-rose-200 text-rose-900",
19
+ orange: "bg-orange-50 border-b border-orange-200 text-orange-900",
20
+ green: "bg-green-50 border-b border-green-200 text-green-900",
21
+ blue: "bg-blue-50 border-b border-blue-200 text-blue-900",
22
+ yellow: "bg-yellow-50 border-b border-yellow-200 text-yellow-900",
23
+ violet: "bg-violet-50 border-b border-violet-200 text-violet-900"
24
+ }
25
+
26
+ # Dimensioni con classi Tailwind dirette
27
+ MODAL_SIZES = {
28
+ small: "max-w-sm",
29
+ medium: "max-w-md",
30
+ large: "max-w-2xl"
31
+ }
32
+
33
+ # Border radius con classi Tailwind dirette
34
+ MODAL_ROUNDED = {
35
+ none: "rounded-none",
36
+ small: "rounded-md",
37
+ medium: "rounded-lg",
38
+ large: "rounded-xl",
39
+ full: "rounded-full"
40
+ }
41
+
42
+ # Inizializzazione del modal component
43
+ def initialize(
44
+ title:,
45
+ theme: :default,
46
+ size: :medium,
47
+ rounded: :medium,
48
+ backdrop: true,
49
+ closable: true,
50
+ classes: nil,
51
+ **html_options
52
+ )
53
+ @title = title
54
+ @theme = theme.to_sym
55
+ @size = size.to_sym
56
+ @rounded = rounded.to_sym
57
+ @backdrop = backdrop
58
+ @closable = closable
59
+ @classes = classes
60
+ @html_options = html_options
61
+
62
+ validate_params
63
+ end
64
+
65
+ # Combina tutte le classi per il backdrop
66
+ def backdrop_classes
67
+ MODAL_BACKDROP_CLASSES
68
+ end
69
+
70
+ # Combina tutte le classi per il contenitore
71
+ def container_classes
72
+ [
73
+ MODAL_CONTAINER_CLASSES,
74
+ get_modal_size_classes,
75
+ get_modal_rounded_classes,
76
+ @classes,
77
+ @html_options[:class]
78
+ ].compact.join(" ")
79
+ end
80
+
81
+ # Combina tutte le classi per l'header
82
+ def header_classes
83
+ [
84
+ "flex items-center justify-between p-6",
85
+ get_modal_theme_classes
86
+ ].compact.join(" ")
87
+ end
88
+
89
+ def get_modal_theme_classes
90
+ MODAL_THEME[@theme] || MODAL_THEME[:default]
91
+ end
92
+
93
+ def get_modal_size_classes
94
+ MODAL_SIZES[@size] || MODAL_SIZES[:medium]
95
+ end
96
+
97
+ def get_modal_rounded_classes
98
+ MODAL_ROUNDED[@rounded] || MODAL_ROUNDED[:medium]
99
+ end
100
+
101
+ # Restituisce gli attributi per il backdrop
102
+ def backdrop_attributes
103
+ {
104
+ class: backdrop_classes,
105
+ 'data-bui-modal-target': 'backdrop'
106
+ }
107
+ end
108
+
109
+ # Restituisce gli attributi per il contenitore
110
+ def container_attributes
111
+ {
112
+ class: container_classes,
113
+ role: "dialog",
114
+ "aria-modal": "true",
115
+ "aria-labelledby": "modal-title",
116
+ 'data-bui-modal-target': 'container'
117
+ }
118
+ end
119
+
120
+ # Restituisce gli attributi per l'header
121
+ def header_attributes
122
+ {
123
+ class: header_classes
124
+ }
125
+ end
126
+
127
+ # Verifica se rendere il componente
128
+ def render?
129
+ @title.present?
130
+ end
131
+
132
+ private
133
+
134
+ def validate_params
135
+ validate_theme
136
+ validate_size
137
+ validate_rounded
138
+ end
139
+
140
+ def validate_theme
141
+ unless MODAL_THEME.keys.include?(@theme)
142
+ raise ArgumentError, "Il tema deve essere uno tra: #{MODAL_THEME.keys.join(', ')}"
143
+ end
144
+ end
145
+
146
+ def validate_size
147
+ unless MODAL_SIZES.keys.include?(@size)
148
+ raise ArgumentError, "La dimensione deve essere una tra: #{MODAL_SIZES.keys.join(', ')}"
149
+ end
150
+ end
151
+
152
+ def validate_rounded
153
+ unless MODAL_ROUNDED.keys.include?(@rounded)
154
+ raise ArgumentError, "Il border radius deve essere uno tra: #{MODAL_ROUNDED.keys.join(', ')}"
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
@@ -1,3 +1,11 @@
1
- <div <%= tag.attributes(container_attributes) %>>
2
- <%= content %>
1
+ <div <%= tag.attributes(wrapper_attributes) %>>
2
+ <!-- Navigation Tabs -->
3
+ <div <%= tag.attributes(navigation_attributes) %>>
4
+ <%= navigation %>
5
+ </div>
6
+
7
+ <!-- Tab Panels -->
8
+ <div <%= tag.attributes(panels_attributes) %>>
9
+ <%= panels %>
10
+ </div>
3
11
  </div>
@@ -4,6 +4,8 @@ module BetterUi
4
4
  module General
5
5
  module Tabs
6
6
  class Component < ViewComponent::Base
7
+ renders_one :navigation
8
+ renders_one :panels
7
9
  TABS_VARIANT = {
8
10
  pills: 'bg-gray-100 rounded-lg p-1',
9
11
  underline: 'border-b border-gray-200',
@@ -34,12 +36,14 @@ module BetterUi
34
36
  vertical: 'flex-col'
35
37
  }.freeze
36
38
 
37
- def initialize(variant: :pills, theme: :default, size: :medium, orientation: :horizontal, classes: '', **options)
39
+ def initialize(variant: :pills, theme: :default, size: :medium, orientation: :horizontal,
40
+ navigation_classes: '', panels_classes: 'mt-4', **options)
38
41
  @variant = variant
39
42
  @theme = theme
40
43
  @size = size
41
44
  @orientation = orientation
42
- @classes = classes
45
+ @navigation_classes = navigation_classes
46
+ @panels_classes = panels_classes
43
47
  @options = options
44
48
 
45
49
  validate_params
@@ -47,7 +51,7 @@ module BetterUi
47
51
 
48
52
  private
49
53
 
50
- attr_reader :variant, :theme, :size, :orientation, :classes, :options
54
+ attr_reader :variant, :theme, :size, :orientation, :navigation_classes, :panels_classes, :options
51
55
 
52
56
  def validate_params
53
57
  validate_variant
@@ -80,21 +84,35 @@ module BetterUi
80
84
  raise ArgumentError, "Invalid orientation: #{orientation}. Must be one of #{TABS_ORIENTATION.keys}"
81
85
  end
82
86
 
83
- def container_attributes
87
+ # Attributi per il wrapper principale (con data-controller)
88
+ def wrapper_attributes
89
+ {
90
+ 'data-controller': 'bui-tabs'
91
+ }.merge(options)
92
+ end
93
+
94
+ # Attributi per il container della navigazione tabs
95
+ def navigation_attributes
84
96
  base_classes = [
85
97
  'flex',
86
98
  TABS_ORIENTATION[orientation],
87
99
  TABS_VARIANT[variant],
88
100
  TABS_THEME_DEFAULT[theme],
89
101
  TABS_SIZE[size],
90
- classes
102
+ navigation_classes
91
103
  ].compact.join(' ')
92
104
 
93
105
  {
94
106
  class: base_classes,
95
- role: 'tablist',
96
- 'data-controller': 'bui-tabs'
97
- }.merge(options)
107
+ role: 'tablist'
108
+ }
109
+ end
110
+
111
+ # Attributi per il container dei panel
112
+ def panels_attributes
113
+ {
114
+ class: panels_classes
115
+ }
98
116
  end
99
117
  end
100
118
  end
@@ -18,7 +18,7 @@ module BetterUi
18
18
  def panel_attributes
19
19
  base_classes = [
20
20
  'focus:outline-none',
21
- active ? 'block' : 'hidden',
21
+ 'hidden', # Sempre nascosto inizialmente, JavaScript gestisce la visibilità
22
22
  classes
23
23
  ].compact.join(' ')
24
24
 
@@ -92,7 +92,7 @@ module BetterUi
92
92
  'aria-controls': target,
93
93
  'data-bui-tabs-target': 'tab',
94
94
  'data-target': target,
95
- 'data-action': disabled ? '' : 'click->bui-tabs#switchTab',
95
+ 'data-action': disabled ? '' : 'click->bui-tabs#switchTab keydown->bui-tabs#keydown',
96
96
  tabindex: active ? '0' : '-1',
97
97
  id: "tab-#{target}"
98
98
  }.merge(options)
@@ -0,0 +1 @@
1
+ <%= tag.span(text_content, **text_attributes) %>