shadcn_phlexcomponents 0.1.17 → 0.1.19

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 (130) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +321 -23
  3. data/app/javascript/controllers/accordion_controller.js +1 -0
  4. data/app/javascript/controllers/alert_dialog_controller.js +1 -0
  5. data/app/javascript/controllers/avatar_controller.js +1 -0
  6. data/app/javascript/controllers/checkbox_controller.js +1 -0
  7. data/app/javascript/controllers/collapsible_controller.js +1 -0
  8. data/app/javascript/controllers/combobox_controller.js +1 -1
  9. data/app/javascript/controllers/command_controller.js +1 -0
  10. data/app/javascript/controllers/date_picker_controller.js +21 -5
  11. data/app/javascript/controllers/date_range_picker_controller.js +1 -0
  12. data/app/javascript/controllers/dialog_controller.js +1 -0
  13. data/app/javascript/controllers/dropdown_menu_controller.js +1 -0
  14. data/app/javascript/controllers/dropdown_menu_sub_controller.js +1 -0
  15. data/app/javascript/controllers/form_field_controller.js +1 -0
  16. data/app/javascript/controllers/hover_card_controller.js +1 -0
  17. data/app/javascript/controllers/loading_button_controller.js +1 -0
  18. data/app/javascript/controllers/popover_controller.js +1 -0
  19. data/app/javascript/controllers/progress_controller.js +1 -0
  20. data/app/javascript/controllers/radio_group_controller.js +1 -0
  21. data/app/javascript/controllers/select_controller.js +1 -0
  22. data/app/javascript/controllers/slider_controller.js +1 -0
  23. data/app/javascript/controllers/switch_controller.js +1 -0
  24. data/app/javascript/controllers/tabs_controller.js +1 -0
  25. data/app/javascript/controllers/theme_switcher_controller.js +1 -0
  26. data/app/javascript/controllers/toast_container_controller.js +1 -0
  27. data/app/javascript/controllers/toast_controller.js +1 -0
  28. data/app/javascript/controllers/toggle_controller.js +1 -0
  29. data/app/javascript/controllers/toggle_group_controller.js +1 -0
  30. data/app/javascript/controllers/tooltip_controller.js +2 -1
  31. data/app/javascript/shadcn_phlexcomponents.js +27 -60
  32. data/app/javascript/utils/command.js +0 -2
  33. data/app/javascript/utils/floating_ui.js +10 -17
  34. data/app/stylesheets/date_picker.css +1 -1
  35. data/app/stylesheets/shadcn_phlexcomponents.css +173 -0
  36. data/app/typescript/controllers/accordion_controller.ts +2 -0
  37. data/app/typescript/controllers/alert_dialog_controller.ts +2 -0
  38. data/app/typescript/controllers/avatar_controller.ts +2 -0
  39. data/app/typescript/controllers/checkbox_controller.ts +2 -0
  40. data/app/typescript/controllers/collapsible_controller.ts +2 -0
  41. data/app/typescript/controllers/combobox_controller.ts +2 -1
  42. data/app/typescript/controllers/command_controller.ts +2 -0
  43. data/app/typescript/controllers/date_picker_controller.ts +27 -7
  44. data/app/typescript/controllers/date_range_picker_controller.ts +2 -0
  45. data/app/typescript/controllers/dialog_controller.ts +2 -0
  46. data/app/typescript/controllers/dropdown_menu_controller.ts +2 -0
  47. data/app/typescript/controllers/dropdown_menu_sub_controller.ts +2 -0
  48. data/app/typescript/controllers/form_field_controller.ts +2 -0
  49. data/app/typescript/controllers/hover_card_controller.ts +2 -0
  50. data/app/typescript/controllers/loading_button_controller.ts +2 -0
  51. data/app/typescript/controllers/popover_controller.ts +2 -0
  52. data/app/typescript/controllers/progress_controller.ts +2 -0
  53. data/app/typescript/controllers/radio_group_controller.ts +2 -0
  54. data/app/typescript/controllers/select_controller.ts +2 -0
  55. data/app/typescript/controllers/slider_controller.ts +2 -0
  56. data/app/typescript/controllers/switch_controller.ts +2 -0
  57. data/app/typescript/controllers/tabs_controller.ts +2 -0
  58. data/app/typescript/controllers/theme_switcher_controller.ts +2 -0
  59. data/app/typescript/controllers/toast_container_controller.ts +2 -0
  60. data/app/typescript/controllers/toast_controller.ts +2 -0
  61. data/app/typescript/controllers/toggle_controller.ts +2 -0
  62. data/app/typescript/controllers/toggle_group_controller.ts +2 -0
  63. data/app/typescript/controllers/tooltip_controller.ts +3 -1
  64. data/app/typescript/shadcn_phlexcomponents.ts +27 -61
  65. data/app/typescript/utils/command.ts +0 -2
  66. data/app/typescript/utils/floating_ui.ts +11 -20
  67. data/app/typescript/utils/index.ts +1 -1
  68. data/lib/install/upgrade_shadcn_phlexcomponents.rb +28 -0
  69. data/lib/shadcn_phlexcomponents/components/accordion.rb +56 -13
  70. data/lib/shadcn_phlexcomponents/components/alert.rb +35 -16
  71. data/lib/shadcn_phlexcomponents/components/alert_dialog.rb +58 -18
  72. data/lib/shadcn_phlexcomponents/components/aspect_ratio.rb +33 -2
  73. data/lib/shadcn_phlexcomponents/components/avatar.rb +24 -7
  74. data/lib/shadcn_phlexcomponents/components/badge.rb +23 -18
  75. data/lib/shadcn_phlexcomponents/components/base.rb +2 -2
  76. data/lib/shadcn_phlexcomponents/components/breadcrumb.rb +46 -6
  77. data/lib/shadcn_phlexcomponents/components/button.rb +32 -27
  78. data/lib/shadcn_phlexcomponents/components/card.rb +59 -10
  79. data/lib/shadcn_phlexcomponents/components/checkbox.rb +51 -30
  80. data/lib/shadcn_phlexcomponents/components/checkbox_group.rb +24 -4
  81. data/lib/shadcn_phlexcomponents/components/combobox.rb +224 -81
  82. data/lib/shadcn_phlexcomponents/components/command.rb +167 -63
  83. data/lib/shadcn_phlexcomponents/components/date_picker.rb +140 -48
  84. data/lib/shadcn_phlexcomponents/components/date_range_picker.rb +26 -44
  85. data/lib/shadcn_phlexcomponents/components/dialog.rb +86 -32
  86. data/lib/shadcn_phlexcomponents/components/dropdown_menu.rb +74 -25
  87. data/lib/shadcn_phlexcomponents/components/dropdown_menu_sub.rb +52 -24
  88. data/lib/shadcn_phlexcomponents/components/form/form_checkbox.rb +1 -1
  89. data/lib/shadcn_phlexcomponents/components/form/form_checkbox_group.rb +1 -1
  90. data/lib/shadcn_phlexcomponents/components/form/form_combobox.rb +1 -1
  91. data/lib/shadcn_phlexcomponents/components/form/form_date_picker.rb +1 -1
  92. data/lib/shadcn_phlexcomponents/components/form/form_date_range_picker.rb +1 -1
  93. data/lib/shadcn_phlexcomponents/components/form/form_error.rb +8 -1
  94. data/lib/shadcn_phlexcomponents/components/form/form_helpers.rb +3 -2
  95. data/lib/shadcn_phlexcomponents/components/form/form_hint.rb +8 -1
  96. data/lib/shadcn_phlexcomponents/components/form/form_input.rb +1 -1
  97. data/lib/shadcn_phlexcomponents/components/form/form_radio_group.rb +1 -1
  98. data/lib/shadcn_phlexcomponents/components/form/form_select.rb +1 -1
  99. data/lib/shadcn_phlexcomponents/components/form/form_slider.rb +1 -1
  100. data/lib/shadcn_phlexcomponents/components/form/form_switch.rb +1 -1
  101. data/lib/shadcn_phlexcomponents/components/form/form_textarea.rb +1 -1
  102. data/lib/shadcn_phlexcomponents/components/form.rb +22 -6
  103. data/lib/shadcn_phlexcomponents/components/hover_card.rb +48 -18
  104. data/lib/shadcn_phlexcomponents/components/input.rb +13 -8
  105. data/lib/shadcn_phlexcomponents/components/label.rb +9 -4
  106. data/lib/shadcn_phlexcomponents/components/link.rb +8 -1
  107. data/lib/shadcn_phlexcomponents/components/pagination.rb +34 -6
  108. data/lib/shadcn_phlexcomponents/components/popover.rb +43 -13
  109. data/lib/shadcn_phlexcomponents/components/progress.rb +37 -6
  110. data/lib/shadcn_phlexcomponents/components/radio_group.rb +41 -15
  111. data/lib/shadcn_phlexcomponents/components/select.rb +99 -42
  112. data/lib/shadcn_phlexcomponents/components/separator.rb +9 -4
  113. data/lib/shadcn_phlexcomponents/components/sheet.rb +94 -28
  114. data/lib/shadcn_phlexcomponents/components/skeleton.rb +8 -1
  115. data/lib/shadcn_phlexcomponents/components/switch.rb +45 -17
  116. data/lib/shadcn_phlexcomponents/components/table.rb +84 -17
  117. data/lib/shadcn_phlexcomponents/components/tabs.rb +36 -12
  118. data/lib/shadcn_phlexcomponents/components/textarea.rb +12 -7
  119. data/lib/shadcn_phlexcomponents/components/toast.rb +46 -20
  120. data/lib/shadcn_phlexcomponents/components/toast_container.rb +19 -14
  121. data/lib/shadcn_phlexcomponents/components/toggle.rb +29 -24
  122. data/lib/shadcn_phlexcomponents/components/tooltip.rb +49 -14
  123. data/lib/shadcn_phlexcomponents/configuration.rb +46 -0
  124. data/lib/shadcn_phlexcomponents/initializers/shadcn_phlexcomponents.rb +28 -0
  125. data/lib/shadcn_phlexcomponents/version.rb +1 -1
  126. data/lib/shadcn_phlexcomponents.rb +12 -1
  127. data/lib/tasks/upgrade.rake +10 -0
  128. metadata +16 -14
  129. data/app/typescript/controllers/sidebar_controller.ts +0 -39
  130. data/app/typescript/controllers/sidebar_trigger_controller.ts +0 -21
@@ -2,7 +2,14 @@
2
2
 
3
3
  module ShadcnPhlexcomponents
4
4
  class DateRangePicker < Base
5
- class_variants(base: "w-full")
5
+ class_variants(
6
+ **(
7
+ ShadcnPhlexcomponents.configuration.date_picker&.dig(:root) ||
8
+ {
9
+ base: "w-full",
10
+ }
11
+ ),
12
+ )
6
13
 
7
14
  def initialize(
8
15
  name: nil,
@@ -27,11 +34,16 @@ module ShadcnPhlexcomponents
27
34
  if value
28
35
  value = value.map do |v|
29
36
  if v.is_a?(String)
30
- DateTime.parse(v) rescue nil
37
+ begin
38
+ # Use Time.zone.parse to ensure consistent timezone handling
39
+ Time.zone ? Time.zone.parse(v) : Time.parse(v)
40
+ rescue
41
+ nil
42
+ end
31
43
  else
32
44
  v
33
45
  end
34
- end
46
+ end
35
47
  end
36
48
 
37
49
  @name = name ? name[0] : nil
@@ -64,7 +76,7 @@ module ShadcnPhlexcomponents
64
76
 
65
77
  def view_template(&)
66
78
  div(**@attributes) do
67
- overlay('date-range-picker')
79
+ overlay("date-range-picker")
68
80
 
69
81
  input(
70
82
  type: :hidden,
@@ -83,61 +95,31 @@ module ShadcnPhlexcomponents
83
95
  if @select_only
84
96
  # For select_only date picker, id is passed to button so that clicking on its
85
97
  # label will trigger the popover to appear
86
- DateRangePickerTrigger(
98
+ DatePickerTrigger(
87
99
  disabled: @disabled,
88
- aria_id: @aria_id,
89
100
  select_only: @select_only,
90
101
  id: @id,
91
102
  placeholder: @placeholder,
103
+ stimulus_controller_name: "date-range-picker",
104
+ aria_id: @aria_id,
92
105
  )
93
106
  else
94
- div(
95
- class: <<~HEREDOC,
96
- focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]
97
- data-[focus=true]:border-ring data-[focus=true]:ring-ring/50 data-[focus=true]:ring-[3px]
98
- data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 flex shadow-xs transition-[color,box-shadow]
99
- rounded-md border bg-transparent dark:bg-input/30 border-input outline-none h-9 flex items-center
100
- aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive
101
- HEREDOC
102
- data: { date_range_picker_target: "inputContainer", disabled: @disabled },
103
- ) do
104
- input(
105
- id: @id,
106
- placeholder: @placeholder || "#{@format} - #{@format}",
107
- type: :text,
108
- class: "md:text-sm placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground flex h-9 w-full min-w-0 text-base outline-none px-3 py-1",
109
- disabled: @disabled,
110
- data: {
111
- date_range_picker_target: "input",
112
- action: "input->date-range-picker#inputDate
113
- blur->date-range-picker#inputBlur
114
- focus->date-range-picker#setContainerFocus",
115
- },
116
- )
117
107
 
118
- DateRangePickerTrigger(
108
+ DatePickerInputContainer(disabled: @disabled, stimulus_controller_name: "date-range-picker") do
109
+ DatePickerInput(id: @id, placeholder: @placeholder, format: "#{@format} - #{@format}", disabled: @disabled, stimulus_controller_name: "date-range-picker", aria_id: @aria_id)
110
+
111
+ DatePickerTrigger(
119
112
  disabled: @disabled,
120
- aria_id: @aria_id,
121
113
  select_only: @select_only,
122
114
  placeholder: @placeholder,
115
+ stimulus_controller_name: "date-range-picker",
116
+ aria_id: @aria_id,
123
117
  )
124
118
  end
125
119
  end
126
120
 
127
- DateRangePickerContent(aria_id: @aria_id)
121
+ DatePickerContent(stimulus_controller_name: "date-range-picker", aria_id: @aria_id)
128
122
  end
129
123
  end
130
124
  end
131
-
132
- class DateRangePickerTrigger < DatePickerTrigger
133
- def stimulus_controller_name
134
- "date-range-picker"
135
- end
136
- end
137
-
138
- class DateRangePickerContent < DatePickerContent
139
- def stimulus_controller_name
140
- "date-range-picker"
141
- end
142
- end
143
125
  end
@@ -2,7 +2,14 @@
2
2
 
3
3
  module ShadcnPhlexcomponents
4
4
  class Dialog < Base
5
- class_variants(base: "inline-flex max-w-fit")
5
+ class_variants(
6
+ **(
7
+ ShadcnPhlexcomponents.configuration.dialog&.dig(:root) ||
8
+ {
9
+ base: "inline-flex max-w-fit",
10
+ }
11
+ ),
12
+ )
6
13
 
7
14
  def initialize(open: false, **attributes)
8
15
  @open = open
@@ -42,15 +49,15 @@ module ShadcnPhlexcomponents
42
49
  {
43
50
  data: {
44
51
  controller: "dialog",
45
- dialog_is_open_value: @open.to_s
46
- }
52
+ dialog_is_open_value: @open.to_s,
53
+ },
47
54
  }
48
55
  end
49
56
 
50
57
  def view_template(&)
51
58
  div(**@attributes) do
52
59
  overlay("dialog")
53
-
60
+
54
61
  yield
55
62
  end
56
63
  end
@@ -71,10 +78,10 @@ module ShadcnPhlexcomponents
71
78
  expanded: "false",
72
79
  controls: "#{@aria_id}-content",
73
80
  },
74
- data: {
81
+ data: {
75
82
  as_child: @as_child.to_s,
76
83
  dialog_target: "trigger",
77
- action: "click->dialog#open"
84
+ action: "click->dialog#open",
78
85
  },
79
86
  }
80
87
  end
@@ -97,13 +104,18 @@ module ShadcnPhlexcomponents
97
104
 
98
105
  class DialogContent < Base
99
106
  class_variants(
100
- base: <<~HEREDOC,
101
- bg-background data-[state=open]:animate-in data-[state=closed]:animate-out
102
- data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95
103
- data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)]
104
- translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg
105
- pointer-events-auto outline-none
106
- HEREDOC
107
+ **(
108
+ ShadcnPhlexcomponents.configuration.dialog&.dig(:content) ||
109
+ {
110
+ base: <<~HEREDOC,
111
+ bg-background data-[state=open]:animate-in data-[state=closed]:animate-out
112
+ data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95
113
+ data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)]
114
+ translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg
115
+ pointer-events-auto outline-none
116
+ HEREDOC
117
+ }
118
+ ),
107
119
  )
108
120
 
109
121
  def initialize(aria_id: nil, **attributes)
@@ -122,7 +134,7 @@ module ShadcnPhlexcomponents
122
134
  },
123
135
  data: {
124
136
  state: "closed",
125
- dialog_target: "content"
137
+ dialog_target: "content",
126
138
  },
127
139
  }
128
140
  end
@@ -131,26 +143,20 @@ module ShadcnPhlexcomponents
131
143
  div(style: { display: "none" }, **@attributes) do
132
144
  yield
133
145
 
134
- button(
135
- class: <<~HEREDOC,
136
- ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground
137
- absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2
138
- focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none
139
- [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4
140
- HEREDOC
141
- data: {
142
- action: "click->dialog#close",
143
- },
144
- ) do
145
- icon("x", class: "size-4")
146
- span(class: "sr-only") { "close" }
147
- end
146
+ DialogCloseIcon()
148
147
  end
149
148
  end
150
149
  end
151
150
 
152
151
  class DialogHeader < Base
153
- class_variants(base: "flex flex-col gap-2 text-center sm:text-left")
152
+ class_variants(
153
+ **(
154
+ ShadcnPhlexcomponents.configuration.dialog&.dig(:header) ||
155
+ {
156
+ base: "flex flex-col gap-2 text-center sm:text-left",
157
+ }
158
+ ),
159
+ )
154
160
 
155
161
  def view_template(&)
156
162
  div(**@attributes, &)
@@ -158,7 +164,14 @@ module ShadcnPhlexcomponents
158
164
  end
159
165
 
160
166
  class DialogTitle < Base
161
- class_variants(base: "text-lg leading-none font-semibold")
167
+ class_variants(
168
+ **(
169
+ ShadcnPhlexcomponents.configuration.dialog&.dig(:title) ||
170
+ {
171
+ base: "text-lg leading-none font-semibold",
172
+ }
173
+ ),
174
+ )
162
175
 
163
176
  def initialize(aria_id: nil, **attributes)
164
177
  @aria_id = aria_id
@@ -177,7 +190,14 @@ module ShadcnPhlexcomponents
177
190
  end
178
191
 
179
192
  class DialogDescription < Base
180
- class_variants(base: "text-muted-foreground text-sm")
193
+ class_variants(
194
+ **(
195
+ ShadcnPhlexcomponents.configuration.dialog&.dig(:description) ||
196
+ {
197
+ base: "text-muted-foreground text-sm",
198
+ }
199
+ ),
200
+ )
181
201
 
182
202
  def initialize(aria_id: nil, **attributes)
183
203
  @aria_id = aria_id
@@ -196,7 +216,14 @@ module ShadcnPhlexcomponents
196
216
  end
197
217
 
198
218
  class DialogFooter < Base
199
- class_variants(base: "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end")
219
+ class_variants(
220
+ **(
221
+ ShadcnPhlexcomponents.configuration.dialog&.dig(:footer) ||
222
+ {
223
+ base: "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
224
+ }
225
+ ),
226
+ )
200
227
 
201
228
  def view_template(&)
202
229
  div(**@attributes, &)
@@ -233,4 +260,31 @@ module ShadcnPhlexcomponents
233
260
  end
234
261
  end
235
262
  end
263
+
264
+ class DialogCloseIcon < Base
265
+ class_variants(
266
+ **(
267
+ ShadcnPhlexcomponents.configuration.dialog&.dig(:close_icon) ||
268
+ {
269
+ base: <<~HEREDOC,
270
+ ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground
271
+ absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2
272
+ focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none
273
+ [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4
274
+ HEREDOC
275
+ }
276
+ ),
277
+ )
278
+
279
+ def default_attributes
280
+ { data: { action: "click->dialog#close" } }
281
+ end
282
+
283
+ def view_template
284
+ button(**@attributes) do
285
+ icon("x", class: "size-4")
286
+ span(class: "sr-only") { "close" }
287
+ end
288
+ end
289
+ end
236
290
  end
@@ -2,7 +2,14 @@
2
2
 
3
3
  module ShadcnPhlexcomponents
4
4
  class DropdownMenu < Base
5
- class_variants(base: "inline-flex max-w-fit")
5
+ class_variants(
6
+ **(
7
+ ShadcnPhlexcomponents.configuration.dropdown_menu&.dig(:root) ||
8
+ {
9
+ base: "inline-flex max-w-fit",
10
+ }
11
+ ),
12
+ )
6
13
 
7
14
  def initialize(open: false, **attributes)
8
15
  @aria_id = "dropdown-menu-#{SecureRandom.hex(5)}"
@@ -104,14 +111,19 @@ module ShadcnPhlexcomponents
104
111
 
105
112
  class DropdownMenuContent < Base
106
113
  class_variants(
107
- base: <<~HEREDOC,
108
- bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out
109
- data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95
110
- data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2
111
- data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50
112
- max-h-(--radix-popper-available-height) min-w-[8rem] origin-(--radix-popper-transform-origin)
113
- overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md pointer-events-auto outline-none
114
- HEREDOC
114
+ **(
115
+ ShadcnPhlexcomponents.configuration.dropdown_menu&.dig(:content) ||
116
+ {
117
+ base: <<~HEREDOC,
118
+ bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out
119
+ data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95
120
+ data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2
121
+ data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50
122
+ max-h-(--radix-popper-available-height) min-w-[8rem] origin-(--radix-popper-transform-origin)
123
+ overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md pointer-events-auto outline-none
124
+ HEREDOC
125
+ }
126
+ ),
115
127
  )
116
128
 
117
129
  def initialize(side: :bottom, align: :center, aria_id: nil, **attributes)
@@ -122,11 +134,7 @@ module ShadcnPhlexcomponents
122
134
  end
123
135
 
124
136
  def view_template(&)
125
- div(
126
- style: { display: "none" },
127
- class: "fixed top-0 left-0 w-max z-50",
128
- data: { dropdown_menu_target: "contentContainer" },
129
- ) do
137
+ DropdownMenuContentContainer do
130
138
  div(**@attributes, &)
131
139
  end
132
140
  end
@@ -156,7 +164,14 @@ module ShadcnPhlexcomponents
156
164
  end
157
165
 
158
166
  class DropdownMenuLabel < Base
159
- class_variants(base: "px-2 py-1.5 text-sm font-medium data-[inset]:pl-8")
167
+ class_variants(
168
+ **(
169
+ ShadcnPhlexcomponents.configuration.dropdown_menu&.dig(:label) ||
170
+ {
171
+ base: "px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
172
+ }
173
+ ),
174
+ )
160
175
 
161
176
  def view_template(&)
162
177
  div(**@attributes, &)
@@ -165,15 +180,20 @@ module ShadcnPhlexcomponents
165
180
 
166
181
  class DropdownMenuItem < Base
167
182
  class_variants(
168
- base: <<~HEREDOC,
169
- focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive
170
- data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20
171
- data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive
172
- [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2
173
- rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none
174
- data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0
175
- [&_svg:not([class*='size-'])]:size-4
176
- HEREDOC
183
+ **(
184
+ ShadcnPhlexcomponents.configuration.dropdown_menu&.dig(:item) ||
185
+ {
186
+ base: <<~HEREDOC,
187
+ focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive
188
+ data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20
189
+ data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive
190
+ [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2
191
+ rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none
192
+ data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0
193
+ [&_svg:not([class*='size-'])]:size-4
194
+ HEREDOC
195
+ }
196
+ ),
177
197
  )
178
198
 
179
199
  def initialize(as_child: false, variant: :default, disabled: false, **attributes)
@@ -255,7 +275,14 @@ module ShadcnPhlexcomponents
255
275
  end
256
276
 
257
277
  class DropdownMenuSeparator < Base
258
- class_variants(base: "bg-border -mx-1 my-1 h-px")
278
+ class_variants(
279
+ **(
280
+ ShadcnPhlexcomponents.configuration.dropdown_menu&.dig(:separator) ||
281
+ {
282
+ base: "bg-border -mx-1 my-1 h-px",
283
+ }
284
+ ),
285
+ )
259
286
 
260
287
  def view_template(&)
261
288
  div(**@attributes, &)
@@ -280,4 +307,26 @@ module ShadcnPhlexcomponents
280
307
  div(**@attributes, &)
281
308
  end
282
309
  end
310
+
311
+ class DropdownMenuContentContainer < Base
312
+ class_variants(
313
+ **(
314
+ ShadcnPhlexcomponents.configuration.dropdown_menu&.dig(:content_container) ||
315
+ {
316
+ base: "fixed top-0 left-0 w-max z-50",
317
+ }
318
+ ),
319
+ )
320
+
321
+ def default_attributes
322
+ {
323
+ style: { display: "none" },
324
+ data: { dropdown_menu_target: "contentContainer" },
325
+ }
326
+ end
327
+
328
+ def view_template(&)
329
+ div(**@attributes, &)
330
+ end
331
+ end
283
332
  end
@@ -31,10 +31,15 @@ module ShadcnPhlexcomponents
31
31
 
32
32
  class DropdownMenuSubTrigger < Base
33
33
  class_variants(
34
- base: <<~HEREDOC,
35
- focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground
36
- flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8
37
- HEREDOC
34
+ **(
35
+ ShadcnPhlexcomponents.configuration.dropdown_menu_sub&.dig(:trigger) ||
36
+ {
37
+ base: <<~HEREDOC,
38
+ focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground
39
+ flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8
40
+ HEREDOC
41
+ }
42
+ ),
38
43
  )
39
44
 
40
45
  def initialize(aria_id: nil, **attributes)
@@ -42,14 +47,6 @@ module ShadcnPhlexcomponents
42
47
  super(**attributes)
43
48
  end
44
49
 
45
- def view_template(&)
46
- div(**@attributes) do
47
- yield
48
-
49
- icon("chevron-right", class: "ml-auto size-4")
50
- end
51
- end
52
-
53
50
  def default_attributes
54
51
  {
55
52
  id: "#{@aria_id}-trigger",
@@ -80,17 +77,30 @@ module ShadcnPhlexcomponents
80
77
  },
81
78
  }
82
79
  end
80
+
81
+ def view_template(&)
82
+ div(**@attributes) do
83
+ yield
84
+
85
+ icon("chevron-right", class: "ml-auto size-4")
86
+ end
87
+ end
83
88
  end
84
89
 
85
90
  class DropdownMenuSubContent < Base
86
91
  class_variants(
87
- base: <<~HEREDOC,
88
- bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out
89
- data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95
90
- data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2
91
- data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem]
92
- origin-(--radix-popper-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg outline-none
93
- HEREDOC
92
+ **(
93
+ ShadcnPhlexcomponents.configuration.dropdown_menu_sub&.dig(:content) ||
94
+ {
95
+ base: <<~HEREDOC,
96
+ bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out
97
+ data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95
98
+ data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2
99
+ data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem]
100
+ origin-(--radix-popper-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg outline-none
101
+ HEREDOC
102
+ }
103
+ ),
94
104
  )
95
105
 
96
106
  def initialize(aria_id: nil, side: :right, align: :start, **attributes)
@@ -124,13 +134,31 @@ module ShadcnPhlexcomponents
124
134
  end
125
135
 
126
136
  def view_template(&)
127
- div(
128
- style: { display: "none" },
129
- class: "fixed top-0 left-0 w-max z-50",
130
- data: { dropdown_menu_sub_target: "contentContainer" },
131
- ) do
137
+ DropdownMenuSubContentContainer do
132
138
  div(**@attributes, &)
133
139
  end
134
140
  end
135
141
  end
142
+
143
+ class DropdownMenuSubContentContainer < Base
144
+ class_variants(
145
+ **(
146
+ ShadcnPhlexcomponents.configuration.dropdown_menu_sub&.dig(:content_container) ||
147
+ {
148
+ base: "fixed top-0 left-0 w-max z-50",
149
+ }
150
+ ),
151
+ )
152
+
153
+ def default_attributes
154
+ {
155
+ style: { display: "none" },
156
+ data: { dropdown_menu_sub_target: "contentContainer" },
157
+ }
158
+ end
159
+
160
+ def view_template(&)
161
+ div(**@attributes, &)
162
+ end
163
+ end
136
164
  end
@@ -55,7 +55,7 @@ module ShadcnPhlexcomponents
55
55
  @id ||= field_id(@object_name, @method)
56
56
  @name ||= field_name(@object_name, @method)
57
57
 
58
- div(class: "space-y-2") do
58
+ FormField do
59
59
  div(class: "flex items-top space-x-2") do
60
60
  div(class: "grid gap-1.5 relative", data: label_and_hint_container_attributes) do
61
61
  @attributes[:class] = "#{@attributes[:class]} -mt-[1.5px] absolute top-0 left-0"
@@ -81,7 +81,7 @@ module ShadcnPhlexcomponents
81
81
  @id ||= field_id(@object_name, @method)
82
82
  @name ||= field_name(@object_name, @method)
83
83
 
84
- div(class: "space-y-2", data: label_and_hint_container_attributes) do
84
+ FormField(data: label_and_hint_container_attributes) do
85
85
  render_label(&)
86
86
 
87
87
  CheckboxGroup(
@@ -49,7 +49,7 @@ module ShadcnPhlexcomponents
49
49
  @id ||= field_id(@object_name, @method)
50
50
  @name ||= field_name(@object_name, @method)
51
51
 
52
- div(class: "space-y-2", data: label_and_hint_container_attributes) do
52
+ FormField(data: label_and_hint_container_attributes) do
53
53
  render_label(&)
54
54
 
55
55
  Combobox(id: @id, name: @name, value: @value, aria: aria_attributes, **@attributes) do |c|
@@ -35,7 +35,7 @@ module ShadcnPhlexcomponents
35
35
  @id ||= field_id(@object_name, @method)
36
36
  @name ||= field_name(@object_name, @method)
37
37
 
38
- div(class: "space-y-2", data: label_and_hint_container_attributes) do
38
+ FormField(data: label_and_hint_container_attributes) do
39
39
  render_label(&)
40
40
  DatePicker(id: @id, name: @name, value: @value, aria: aria_attributes, **@attributes)
41
41
  render_hint(&)
@@ -65,7 +65,7 @@ module ShadcnPhlexcomponents
65
65
  field_name(@object_name, @end_method),
66
66
  ]
67
67
 
68
- div(class: "space-y-2", data: label_and_hint_container_attributes) do
68
+ FormField(data: label_and_hint_container_attributes) do
69
69
  render_label(&)
70
70
  DateRangePicker(
71
71
  id: @id,
@@ -2,7 +2,14 @@
2
2
 
3
3
  module ShadcnPhlexcomponents
4
4
  class FormError < Base
5
- class_variants(base: "text-destructive text-sm")
5
+ class_variants(
6
+ **(
7
+ ShadcnPhlexcomponents.configuration.form&.dig(:error) ||
8
+ {
9
+ base: "text-destructive text-sm",
10
+ }
11
+ ),
12
+ )
6
13
 
7
14
  def initialize(message, aria_id: nil, **attributes)
8
15
  @message = message
@@ -25,12 +25,13 @@ module ShadcnPhlexcomponents
25
25
 
26
26
  def hint(text = nil, **attributes, &)
27
27
  @yield_hint = true
28
+ @hint = true
28
29
  attrs = hint_attributes(**attributes)
29
30
 
30
31
  if text
31
- FormHint(text, **attrs)
32
+ FormHint(text, aria_id: @aria_id, **attrs)
32
33
  else
33
- FormHint(**attrs, &)
34
+ FormHint(aria_id: @aria_id, **attrs, &)
34
35
  end
35
36
  end
36
37
 
@@ -2,7 +2,14 @@
2
2
 
3
3
  module ShadcnPhlexcomponents
4
4
  class FormHint < Base
5
- class_variants(base: "text-muted-foreground text-sm")
5
+ class_variants(
6
+ **(
7
+ ShadcnPhlexcomponents.configuration.form&.dig(:hint) ||
8
+ {
9
+ base: "text-muted-foreground text-sm",
10
+ }
11
+ ),
12
+ )
6
13
 
7
14
  def initialize(message = nil, aria_id: nil, **attributes)
8
15
  @message = message
@@ -37,7 +37,7 @@ module ShadcnPhlexcomponents
37
37
  @id ||= field_id(@object_name, @method)
38
38
  @name ||= field_name(@object_name, @method)
39
39
 
40
- div(class: "space-y-2", data: label_and_hint_container_attributes) do
40
+ FormField(data: label_and_hint_container_attributes) do
41
41
  render_label(&)
42
42
  Input(type: @type, id: @id, name: @name, value: @value, aria: aria_attributes, **@attributes)
43
43
  render_hint(&)