shadcn_phlexcomponents 0.1.11 → 0.1.14
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/app/javascript/controllers/accordion_controller.ts +65 -62
- data/app/javascript/controllers/alert_dialog_controller.ts +12 -0
- data/app/javascript/controllers/avatar_controller.ts +7 -2
- data/app/javascript/controllers/checkbox_controller.ts +11 -4
- data/app/javascript/controllers/collapsible_controller.ts +12 -5
- data/app/javascript/controllers/combobox_controller.ts +270 -39
- data/app/javascript/controllers/command_controller.ts +223 -51
- data/app/javascript/controllers/date_picker_controller.ts +185 -125
- data/app/javascript/controllers/date_range_picker_controller.ts +89 -79
- data/app/javascript/controllers/dialog_controller.ts +59 -57
- data/app/javascript/controllers/dropdown_menu_controller.ts +212 -36
- data/app/javascript/controllers/dropdown_menu_sub_controller.ts +31 -29
- data/app/javascript/controllers/form_field_controller.ts +6 -1
- data/app/javascript/controllers/hover_card_controller.ts +36 -26
- data/app/javascript/controllers/loading_button_controller.ts +6 -1
- data/app/javascript/controllers/popover_controller.ts +42 -65
- data/app/javascript/controllers/progress_controller.ts +9 -3
- data/app/javascript/controllers/radio_group_controller.ts +16 -9
- data/app/javascript/controllers/select_controller.ts +206 -65
- data/app/javascript/controllers/slider_controller.ts +23 -16
- data/app/javascript/controllers/switch_controller.ts +11 -4
- data/app/javascript/controllers/tabs_controller.ts +26 -18
- data/app/javascript/controllers/theme_switcher_controller.ts +6 -1
- data/app/javascript/controllers/toast_container_controller.ts +6 -1
- data/app/javascript/controllers/toast_controller.ts +7 -1
- data/app/javascript/controllers/toggle_controller.ts +28 -0
- data/app/javascript/controllers/toggle_group_controller.ts +28 -0
- data/app/javascript/controllers/tooltip_controller.ts +43 -31
- data/app/javascript/shadcn_phlexcomponents.ts +29 -25
- data/app/javascript/utils/command.ts +544 -0
- data/app/javascript/utils/floating_ui.ts +196 -0
- data/app/javascript/utils/index.ts +417 -0
- data/app/stylesheets/date_picker.css +118 -0
- data/lib/shadcn_phlexcomponents/alias.rb +3 -0
- data/lib/shadcn_phlexcomponents/components/accordion.rb +2 -1
- data/lib/shadcn_phlexcomponents/components/alert_dialog.rb +18 -15
- data/lib/shadcn_phlexcomponents/components/base.rb +14 -0
- data/lib/shadcn_phlexcomponents/components/collapsible.rb +1 -2
- data/lib/shadcn_phlexcomponents/components/combobox.rb +87 -57
- data/lib/shadcn_phlexcomponents/components/command.rb +77 -47
- data/lib/shadcn_phlexcomponents/components/date_picker.rb +25 -81
- data/lib/shadcn_phlexcomponents/components/date_range_picker.rb +21 -4
- data/lib/shadcn_phlexcomponents/components/dialog.rb +14 -12
- data/lib/shadcn_phlexcomponents/components/dropdown_menu.rb +5 -4
- data/lib/shadcn_phlexcomponents/components/dropdown_menu_sub.rb +2 -1
- data/lib/shadcn_phlexcomponents/components/form/form_combobox.rb +64 -0
- data/lib/shadcn_phlexcomponents/components/form.rb +14 -0
- data/lib/shadcn_phlexcomponents/components/hover_card.rb +3 -2
- data/lib/shadcn_phlexcomponents/components/popover.rb +3 -3
- data/lib/shadcn_phlexcomponents/components/select.rb +10 -25
- data/lib/shadcn_phlexcomponents/components/sheet.rb +15 -11
- data/lib/shadcn_phlexcomponents/components/table.rb +1 -1
- data/lib/shadcn_phlexcomponents/components/tabs.rb +1 -1
- data/lib/shadcn_phlexcomponents/components/toast_container.rb +1 -1
- data/lib/shadcn_phlexcomponents/components/toggle.rb +54 -0
- data/lib/shadcn_phlexcomponents/components/tooltip.rb +3 -2
- data/lib/shadcn_phlexcomponents/engine.rb +1 -5
- data/lib/shadcn_phlexcomponents/version.rb +1 -1
- metadata +9 -4
- data/app/javascript/controllers/command_root_controller.ts +0 -355
- data/app/javascript/controllers/dropdown_menu_root_controller.ts +0 -234
- data/app/javascript/utils.ts +0 -437
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module ShadcnPhlexcomponents
|
4
4
|
class Command < Base
|
5
|
-
class_variants(base: "inline-
|
5
|
+
class_variants(base: "inline-flex max-w-fit")
|
6
6
|
|
7
7
|
MODIFIER_KEYS = [
|
8
8
|
:ctrl,
|
@@ -10,7 +10,16 @@ module ShadcnPhlexcomponents
|
|
10
10
|
:shift,
|
11
11
|
]
|
12
12
|
|
13
|
-
def initialize(
|
13
|
+
def initialize(
|
14
|
+
open: false,
|
15
|
+
modifier_key: nil,
|
16
|
+
shortcut_key: nil,
|
17
|
+
search_path: nil,
|
18
|
+
search_error_text: "Something went wrong, please try again.",
|
19
|
+
search_empty_text: "No results found",
|
20
|
+
search_placeholder_text: "Search...",
|
21
|
+
**attributes
|
22
|
+
)
|
14
23
|
if modifier_key && !MODIFIER_KEYS.include?(modifier_key)
|
15
24
|
raise ArgumentError, "Expected one of #{MODIFIER_KEYS} for \"modifier_key\", got #{modifier_key}"
|
16
25
|
end
|
@@ -19,6 +28,9 @@ module ShadcnPhlexcomponents
|
|
19
28
|
@modifier_key = modifier_key
|
20
29
|
@shortcut_key = shortcut_key
|
21
30
|
@search_path = search_path
|
31
|
+
@search_error_text = search_error_text
|
32
|
+
@search_empty_text = search_empty_text
|
33
|
+
@search_placeholder_text = search_placeholder_text
|
22
34
|
@aria_id = "command-#{SecureRandom.hex(5)}"
|
23
35
|
super(**attributes)
|
24
36
|
end
|
@@ -28,7 +40,14 @@ module ShadcnPhlexcomponents
|
|
28
40
|
end
|
29
41
|
|
30
42
|
def content(**attributes, &)
|
31
|
-
CommandContent(
|
43
|
+
CommandContent(
|
44
|
+
search_error_text: @search_error_text,
|
45
|
+
search_empty_text: @search_empty_text,
|
46
|
+
search_placeholder_text: @search_placeholder_text,
|
47
|
+
aria_id: @aria_id,
|
48
|
+
**attributes,
|
49
|
+
&
|
50
|
+
)
|
32
51
|
end
|
33
52
|
|
34
53
|
def item(**attributes, &)
|
@@ -43,24 +62,24 @@ module ShadcnPhlexcomponents
|
|
43
62
|
CommandGroup(aria_id: @aria_id, **attributes, &)
|
44
63
|
end
|
45
64
|
|
46
|
-
def empty(**attributes, &)
|
47
|
-
CommandEmpty(**attributes, &)
|
48
|
-
end
|
49
|
-
|
50
65
|
def default_attributes
|
51
66
|
{
|
52
67
|
data: {
|
53
68
|
controller: "command",
|
69
|
+
command_is_open_value: @open.to_s,
|
54
70
|
modifier_key: @modifier_key,
|
55
71
|
shortcut_key: @shortcut_key,
|
56
|
-
search_path: @search_path
|
57
|
-
|
58
|
-
},
|
72
|
+
search_path: @search_path
|
73
|
+
}
|
59
74
|
}
|
60
75
|
end
|
61
76
|
|
62
77
|
def view_template(&)
|
63
|
-
div(**@attributes
|
78
|
+
div(**@attributes) do
|
79
|
+
overlay("command")
|
80
|
+
|
81
|
+
yield
|
82
|
+
end
|
64
83
|
end
|
65
84
|
end
|
66
85
|
|
@@ -91,9 +110,8 @@ module ShadcnPhlexcomponents
|
|
91
110
|
controls: "#{@aria_id}-content",
|
92
111
|
},
|
93
112
|
data: {
|
94
|
-
action: "click->command#open",
|
95
113
|
command_target: "trigger",
|
96
|
-
|
114
|
+
action: "click->command#open"
|
97
115
|
},
|
98
116
|
}
|
99
117
|
end
|
@@ -123,18 +141,27 @@ module ShadcnPhlexcomponents
|
|
123
141
|
bg-background bg-clip-padding dark:bg-neutral-900 dark:ring-neutral-800 data-[state=closed]:animate-out#{" "}
|
124
142
|
data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0
|
125
143
|
data-[state=open]:zoom-in-95 duration-200 fixed gap-4 grid left-[50%] max-w-[calc(100%-2rem)] p-2 pb-11 ring-4 ring-neutral-200/80
|
126
|
-
rounded-xl shadow-2xl sm:max-w-lg top-[50%] translate-x-[-50%] translate-y-[-50%] w-full z-50 pointer-events-auto
|
144
|
+
rounded-xl shadow-2xl sm:max-w-lg top-[50%] translate-x-[-50%] translate-y-[-50%] w-full z-50 pointer-events-auto outline-none
|
127
145
|
HEREDOC
|
128
146
|
)
|
129
147
|
|
130
|
-
def initialize(
|
131
|
-
|
148
|
+
def initialize(
|
149
|
+
search_error_text: nil,
|
150
|
+
search_empty_text: nil,
|
151
|
+
search_placeholder_text: nil,
|
152
|
+
aria_id: nil,
|
153
|
+
**attributes
|
154
|
+
)
|
155
|
+
@search_error_text = search_error_text
|
156
|
+
@search_empty_text = search_empty_text
|
157
|
+
@search_placeholder_text = search_placeholder_text
|
132
158
|
@aria_id = aria_id
|
133
159
|
super(**attributes)
|
134
160
|
end
|
135
161
|
|
136
162
|
def default_attributes
|
137
163
|
{
|
164
|
+
style: { display: "none" },
|
138
165
|
id: "#{@aria_id}-content",
|
139
166
|
tabindex: -1,
|
140
167
|
role: "dialog",
|
@@ -143,26 +170,29 @@ module ShadcnPhlexcomponents
|
|
143
170
|
labelledby: "#{@aria_id}-title",
|
144
171
|
},
|
145
172
|
data: {
|
146
|
-
command_target: "content",
|
147
173
|
state: "closed",
|
174
|
+
command_target: "content",
|
148
175
|
action: <<~HEREDOC,
|
149
|
-
command:click:outside->command#
|
176
|
+
command:click:outside->command#clickOutside
|
150
177
|
keydown.up->command#highlightItem:prevent
|
151
178
|
keydown.down->command#highlightItem:prevent
|
152
179
|
keydown.enter->command#select
|
153
180
|
HEREDOC
|
154
|
-
|
155
181
|
},
|
156
182
|
}
|
157
183
|
end
|
158
184
|
|
159
185
|
def view_template(&)
|
160
|
-
|
186
|
+
div(**@attributes) do
|
187
|
+
template do
|
188
|
+
CommandGroup do
|
189
|
+
CommandLabel { "" }
|
190
|
+
end
|
191
|
+
end
|
161
192
|
|
162
|
-
div(class: "#{@class} hidden", **@attributes) do
|
163
193
|
div(class: "text-popover-foreground flex h-full w-full flex-col overflow-hidden bg-transparent") do
|
164
194
|
div(class: "sr-only") do
|
165
|
-
h2(id: "#{@aria_id}-title") { @
|
195
|
+
h2(id: "#{@aria_id}-title") { @search_placeholder_text }
|
166
196
|
p(id: "#{@aria_id}-description") { "Search for a command to run..." }
|
167
197
|
end
|
168
198
|
|
@@ -170,7 +200,7 @@ module ShadcnPhlexcomponents
|
|
170
200
|
class: "sr-only",
|
171
201
|
id: "#{@aria_id}-search-label",
|
172
202
|
for: "#{@aria_id}-search",
|
173
|
-
) { @
|
203
|
+
) { @search_placeholder_text }
|
174
204
|
|
175
205
|
div(class: "flex h-9 items-center gap-2 border px-3 bg-input/50 border-input rounded-md") do
|
176
206
|
icon("search", class: "size-4 shrink-0 opacity-50")
|
@@ -179,7 +209,7 @@ module ShadcnPhlexcomponents
|
|
179
209
|
class: "placeholder:text-muted-foreground flex w-full rounded-md bg-transparent py-3 text-sm
|
180
210
|
outline-hidden disabled:cursor-not-allowed disabled:opacity-50 h-9",
|
181
211
|
id: "#{@aria_id}-search",
|
182
|
-
placeholder: @
|
212
|
+
placeholder: @search_placeholder_text,
|
183
213
|
type: :text,
|
184
214
|
autocomplete: "off",
|
185
215
|
autocorrect: "off",
|
@@ -193,13 +223,21 @@ module ShadcnPhlexcomponents
|
|
193
223
|
},
|
194
224
|
data: {
|
195
225
|
command_target: "searchInput",
|
196
|
-
action: "input->command#search",
|
226
|
+
action: "keydown->command#inputKeydown input->command#search",
|
197
227
|
},
|
198
228
|
)
|
199
229
|
end
|
200
230
|
|
201
|
-
div(class: "p-1 max-h-80 min-h-80 overflow-y-auto",
|
202
|
-
|
231
|
+
div(class: "mt-3 p-1 max-h-80 min-h-80 overflow-y-auto", data: { command_target: "listContainer"}) do
|
232
|
+
CommandText(target: "empty") { @search_empty_text }
|
233
|
+
CommandText(target: "error") { @search_error_text }
|
234
|
+
CommandText(target: "loading") do
|
235
|
+
div(class: "flex justify-center", aria: { label: "Loading" }) do
|
236
|
+
icon("loader-circle", class: "animate-spin")
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
div(id: "#{@aria_id}-list", data: { command_target: "list" }, &)
|
203
241
|
end
|
204
242
|
|
205
243
|
CommandFooter()
|
@@ -251,30 +289,21 @@ module ShadcnPhlexcomponents
|
|
251
289
|
end
|
252
290
|
|
253
291
|
class CommandLabel < Base
|
254
|
-
class_variants(base: "text-muted-foreground text-xs
|
292
|
+
class_variants(base: "text-muted-foreground text-xs px-3 pb-1 text-xs font-medium")
|
255
293
|
|
256
|
-
def initialize(
|
257
|
-
@aria_id = aria_id
|
294
|
+
def initialize( **attributes)
|
258
295
|
super(**attributes)
|
259
296
|
end
|
260
297
|
|
261
298
|
def view_template(&)
|
262
299
|
div(**@attributes, &)
|
263
300
|
end
|
264
|
-
|
265
|
-
def default_attributes
|
266
|
-
{
|
267
|
-
data: {
|
268
|
-
command_target: "label",
|
269
|
-
},
|
270
|
-
}
|
271
|
-
end
|
272
301
|
end
|
273
302
|
|
274
303
|
class CommandGroup < Base
|
275
|
-
class_variants(base: "scroll-mt-16")
|
304
|
+
class_variants(base: "scroll-mt-16 first:pt-0 pt-3")
|
276
305
|
|
277
|
-
def initialize(aria_id
|
306
|
+
def initialize(aria_id: nil, **attributes)
|
278
307
|
@aria_id = aria_id
|
279
308
|
super(**attributes)
|
280
309
|
end
|
@@ -296,22 +325,23 @@ module ShadcnPhlexcomponents
|
|
296
325
|
end
|
297
326
|
end
|
298
327
|
|
299
|
-
class
|
328
|
+
class CommandText < Base
|
300
329
|
class_variants(base: "py-6 text-center text-sm hidden")
|
330
|
+
|
331
|
+
def initialize(target:, **attributes)
|
332
|
+
@target = target
|
333
|
+
super(**attributes)
|
334
|
+
end
|
301
335
|
|
302
336
|
def default_attributes
|
303
337
|
{
|
304
338
|
role: "presentation",
|
305
|
-
data: { command_target:
|
339
|
+
data: { command_target: @target },
|
306
340
|
}
|
307
341
|
end
|
308
342
|
|
309
343
|
def view_template(&)
|
310
|
-
|
311
|
-
div(**@attributes, &)
|
312
|
-
else
|
313
|
-
div(**@attributes) { "No results found" }
|
314
|
-
end
|
344
|
+
div(**@attributes, &)
|
315
345
|
end
|
316
346
|
end
|
317
347
|
|
@@ -4,74 +4,6 @@ module ShadcnPhlexcomponents
|
|
4
4
|
class DatePicker < Base
|
5
5
|
class_variants(base: "w-full")
|
6
6
|
|
7
|
-
class << self
|
8
|
-
button = Button.new
|
9
|
-
|
10
|
-
{
|
11
|
-
input_container: <<~HEREDOC,
|
12
|
-
focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]
|
13
|
-
data-[focus=true]:border-ring data-[focus=true]:ring-ring/50 data-[focus=true]:ring-[3px]
|
14
|
-
data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 flex shadow-xs transition-[color,box-shadow]
|
15
|
-
rounded-md border bg-transparent dark:bg-input/30 border-input outline-none h-9 flex items-center
|
16
|
-
aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive
|
17
|
-
HEREDOC
|
18
|
-
input: <<~HEREDOC,
|
19
|
-
md:text-sm placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground
|
20
|
-
flex h-9 w-full min-w-0 text-base outline-none px-3 py-1#{" "}
|
21
|
-
HEREDOC
|
22
|
-
calendar: {
|
23
|
-
calendar: "relative flex flex-col outline-none",
|
24
|
-
controls: "absolute z-20 -left-1 -right-1 -top-1.5 flex justify-between items-center pt-1.5 px-1 pointer-events-none box-content",
|
25
|
-
grid: "grid gap-4 grid-cols-1 md:grid-cols-2",
|
26
|
-
column: "flex flex-col",
|
27
|
-
header: "relative flex items-center mb-4",
|
28
|
-
headerContent: "grid grid-flow-col gap-x-1 auto-cols-max items-center justify-center px-4 whitespace-pre-wrap grow",
|
29
|
-
month: button.class_variants(variant: :outline, size: :sm, class: "text-xs h-7 bg-transparent"),
|
30
|
-
year: button.class_variants(variant: :outline, size: :sm, class: "text-xs h-7 bg-transparent"),
|
31
|
-
arrowPrev: button.class_variants(variant: :outline, size: :icon, class: "pointer-events-auto size-7 bg-transparent p-0 opacity-50 hover:opacity-100"),
|
32
|
-
arrowNext: button.class_variants(variant: :outline, size: :icon, class: "pointer-events-auto size-7 bg-transparent p-0 opacity-50 hover:opacity-100"),
|
33
|
-
wrapper: "flex items-center content-center h-full",
|
34
|
-
content: "flex flex-col grow h-full",
|
35
|
-
months: "grid gap-2 grid-cols-4 items-center grow",
|
36
|
-
monthsMonth: button.class_variants(variant: :ghost, class: "aria-[selected=true]:text-primary-foreground aria-[selected=true]:bg-primary aria-[selected=true]:hover:text-primary-foreground aria-[selected=true]:hover:bg-primary"),
|
37
|
-
years: "grid gap-2 grid-cols-5 items-center grow",
|
38
|
-
yearsYear: button.class_variants(variant: :ghost, class: "aria-[selected=true]:text-primary-foreground aria-[selected=true]:bg-primary aria-[selected=true]:hover:text-primary-foreground aria-[selected=true]:hover:bg-primary"),
|
39
|
-
week: "grid mb-2 grid-cols-[repeat(7,_1fr)] justify-items-center items-center text-center",
|
40
|
-
weekDay: "text-muted-foreground rounded-md w-8 font-normal text-[0.8rem]",
|
41
|
-
weekNumbers: "vc-week-numbers",
|
42
|
-
weekNumbersTitle: "vc-week-numbers__title",
|
43
|
-
weekNumbersContent: "vc-week-numbers__content",
|
44
|
-
weekNumber: "vc-week-number",
|
45
|
-
dates: "grid gap-y-2 grid-cols-[repeat(7,_1fr)] justify-items-center items-center",
|
46
|
-
date: <<~HEREDOC,
|
47
|
-
vc-date data-[vc-date-selected]:[&_button]:bg-primary#{" "}
|
48
|
-
data-[vc-date-selected]:[&_button]:text-primary-foreground#{" "}
|
49
|
-
data-[vc-date-selected]:[&_button]:hover:bg-primary#{" "}
|
50
|
-
data-[vc-date-selected]:[&_button]:hover:text-primary-foreground#{" "}
|
51
|
-
data-[vc-date-selected]:[&_button]:focus:bg-primary#{" "}
|
52
|
-
data-[vc-date-selected]:[&_button]:focus:text-primary-foreground
|
53
|
-
data-[vc-date-today]:[&_button]:bg-accent
|
54
|
-
data-[vc-date-today]:[&_button]:text-accent-foreground
|
55
|
-
data-[vc-date-month=prev]:[&_button]:text-muted-foreground
|
56
|
-
data-[vc-date-month=next]:[&_button]:text-muted-foreground
|
57
|
-
data-[vc-date-selected='middle']:data-[vc-date-selected]:[&_button]:bg-accent
|
58
|
-
data-[vc-date-selected='middle']:data-[vc-date-selected]:[&_button]:text-accent-foreground
|
59
|
-
data-[vc-date-hover]:[&_button]:bg-accent data-[vc-date-hover]:[&_button]:text-accent-foreground
|
60
|
-
HEREDOC
|
61
|
-
dateBtn: button.class_variants(variant: :ghost, class: "size-8 p-0 font-normal aria-[disabled]:text-muted-foreground aria-[disabled]:opacity-50 aria-[disabled]:pointer-events-none"),
|
62
|
-
datePopup: "vc-date__popup",
|
63
|
-
dateRangeTooltip: "vc-date-range-tooltip",
|
64
|
-
time: "vc-time",
|
65
|
-
timeContent: "vc-time__content",
|
66
|
-
timeHour: "vc-time__hour",
|
67
|
-
timeMinute: "vc-time__minute",
|
68
|
-
timeKeeping: "vc-time__keeping",
|
69
|
-
timeRanges: "vc-time__ranges",
|
70
|
-
timeRange: "vc-time__range",
|
71
|
-
},
|
72
|
-
}
|
73
|
-
end
|
74
|
-
|
75
7
|
def initialize(
|
76
8
|
name: nil,
|
77
9
|
id: nil,
|
@@ -86,6 +18,15 @@ module ShadcnPhlexcomponents
|
|
86
18
|
)
|
87
19
|
@name = name
|
88
20
|
@id = id
|
21
|
+
|
22
|
+
if value
|
23
|
+
value = if value.is_a?(String)
|
24
|
+
DateTime.parse(value) rescue nil
|
25
|
+
else
|
26
|
+
value
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
89
30
|
@value = value&.utc&.iso8601
|
90
31
|
@format = format
|
91
32
|
@select_only = select_only
|
@@ -93,8 +34,7 @@ module ShadcnPhlexcomponents
|
|
93
34
|
@disabled = disabled
|
94
35
|
@mask = mask
|
95
36
|
@aria_id = "date-picker-#{SecureRandom.hex(5)}"
|
96
|
-
@
|
97
|
-
@options = options.merge(styles: @date_picker_styles[:calendar])
|
37
|
+
@options = options
|
98
38
|
super(**attributes)
|
99
39
|
end
|
100
40
|
|
@@ -112,6 +52,8 @@ module ShadcnPhlexcomponents
|
|
112
52
|
|
113
53
|
def view_template(&)
|
114
54
|
div(**@attributes) do
|
55
|
+
overlay("date-picker")
|
56
|
+
|
115
57
|
input(
|
116
58
|
type: :hidden,
|
117
59
|
name: @name,
|
@@ -130,12 +72,19 @@ module ShadcnPhlexcomponents
|
|
130
72
|
placeholder: @placeholder,
|
131
73
|
)
|
132
74
|
else
|
133
|
-
div(class:
|
75
|
+
div(class: <<~HEREDOC,
|
76
|
+
focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]
|
77
|
+
data-[focus=true]:border-ring data-[focus=true]:ring-ring/50 data-[focus=true]:ring-[3px]
|
78
|
+
data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 flex shadow-xs transition-[color,box-shadow]
|
79
|
+
rounded-md border bg-transparent dark:bg-input/30 border-input outline-none h-9 flex items-center
|
80
|
+
aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive
|
81
|
+
HEREDOC
|
82
|
+
data: { date_picker_target: "inputContainer", disabled: @disabled }) do
|
134
83
|
input(
|
135
84
|
id: @id,
|
136
85
|
placeholder: @placeholder || @format,
|
137
86
|
type: :text,
|
138
|
-
class:
|
87
|
+
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",
|
139
88
|
disabled: @disabled,
|
140
89
|
data: {
|
141
90
|
date_picker_target: "input",
|
@@ -223,13 +172,7 @@ module ShadcnPhlexcomponents
|
|
223
172
|
end
|
224
173
|
|
225
174
|
def class_variants(**args)
|
226
|
-
PopoverContent.new.class_variants(
|
227
|
-
class: <<~HEREDOC,
|
228
|
-
fixed left-1/2 top-1/2 shadow-lg -translate-x-1/2 -translate-y-1/2 pointer-events-auto w-max
|
229
|
-
md:relative md:left-[unset] md:top-[unset] md:shadow-md md:translate-x-[unset] md:translate-y-[unset] md:pointer-events-[unset]
|
230
|
-
#{args[:class]}
|
231
|
-
HEREDOC
|
232
|
-
)
|
175
|
+
PopoverContent.new.class_variants(class: "w-fit #{args[:class]}")
|
233
176
|
end
|
234
177
|
|
235
178
|
def default_attributes
|
@@ -252,7 +195,8 @@ module ShadcnPhlexcomponents
|
|
252
195
|
|
253
196
|
def view_template(&)
|
254
197
|
div(
|
255
|
-
|
198
|
+
style: { display: "none" },
|
199
|
+
class: "fixed z-50 top-1/4 left-1/2 -translate-x-1/2 pointer-events-auto md:top-auto md:left-auto md:translate-none md:pointer-events-[unset]",
|
256
200
|
data: { "#{stimulus_controller_name}-target" => "contentContainer" },
|
257
201
|
) do
|
258
202
|
div(**@attributes) do
|
@@ -261,4 +205,4 @@ module ShadcnPhlexcomponents
|
|
261
205
|
end
|
262
206
|
end
|
263
207
|
end
|
264
|
-
end
|
208
|
+
end
|
@@ -24,6 +24,16 @@ module ShadcnPhlexcomponents
|
|
24
24
|
raise ArgumentError, "Expected an array for \"value\", got #{value.class}"
|
25
25
|
end
|
26
26
|
|
27
|
+
if value
|
28
|
+
value = value.map do |v|
|
29
|
+
if v.is_a?(String)
|
30
|
+
DateTime.parse(v) rescue nil
|
31
|
+
else
|
32
|
+
v
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
27
37
|
@name = name ? name[0] : nil
|
28
38
|
@end_name = name ? name[1] : nil
|
29
39
|
@value = (value ? value[0] : nil)&.utc&.iso8601
|
@@ -35,8 +45,7 @@ module ShadcnPhlexcomponents
|
|
35
45
|
@disabled = disabled
|
36
46
|
@mask = mask
|
37
47
|
@aria_id = "date-range-picker-#{SecureRandom.hex(5)}"
|
38
|
-
@
|
39
|
-
@options = options.merge(styles: @date_picker_styles[:calendar])
|
48
|
+
@options = options
|
40
49
|
super(**attributes)
|
41
50
|
end
|
42
51
|
|
@@ -55,6 +64,8 @@ module ShadcnPhlexcomponents
|
|
55
64
|
|
56
65
|
def view_template(&)
|
57
66
|
div(**@attributes) do
|
67
|
+
overlay('date-range-picker')
|
68
|
+
|
58
69
|
input(
|
59
70
|
type: :hidden,
|
60
71
|
name: @name,
|
@@ -81,14 +92,20 @@ module ShadcnPhlexcomponents
|
|
81
92
|
)
|
82
93
|
else
|
83
94
|
div(
|
84
|
-
class:
|
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
|
85
102
|
data: { date_range_picker_target: "inputContainer", disabled: @disabled },
|
86
103
|
) do
|
87
104
|
input(
|
88
105
|
id: @id,
|
89
106
|
placeholder: @placeholder || "#{@format} - #{@format}",
|
90
107
|
type: :text,
|
91
|
-
class:
|
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",
|
92
109
|
disabled: @disabled,
|
93
110
|
data: {
|
94
111
|
date_range_picker_target: "input",
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module ShadcnPhlexcomponents
|
4
4
|
class Dialog < Base
|
5
|
-
class_variants(base: "inline-
|
5
|
+
class_variants(base: "inline-flex max-w-fit")
|
6
6
|
|
7
7
|
def initialize(open: false, **attributes)
|
8
8
|
@open = open
|
@@ -42,13 +42,17 @@ module ShadcnPhlexcomponents
|
|
42
42
|
{
|
43
43
|
data: {
|
44
44
|
controller: "dialog",
|
45
|
-
dialog_is_open_value: @open.to_s
|
46
|
-
}
|
45
|
+
dialog_is_open_value: @open.to_s
|
46
|
+
}
|
47
47
|
}
|
48
48
|
end
|
49
49
|
|
50
50
|
def view_template(&)
|
51
|
-
div(**@attributes
|
51
|
+
div(**@attributes) do
|
52
|
+
overlay("dialog")
|
53
|
+
|
54
|
+
yield
|
55
|
+
end
|
52
56
|
end
|
53
57
|
end
|
54
58
|
|
@@ -67,10 +71,10 @@ module ShadcnPhlexcomponents
|
|
67
71
|
expanded: "false",
|
68
72
|
controls: "#{@aria_id}-content",
|
69
73
|
},
|
70
|
-
data: {
|
71
|
-
action: "click->dialog#open",
|
72
|
-
dialog_target: "trigger",
|
74
|
+
data: {
|
73
75
|
as_child: @as_child.to_s,
|
76
|
+
dialog_target: "trigger",
|
77
|
+
action: "click->dialog#open"
|
74
78
|
},
|
75
79
|
}
|
76
80
|
end
|
@@ -98,7 +102,7 @@ module ShadcnPhlexcomponents
|
|
98
102
|
data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95
|
99
103
|
data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)]
|
100
104
|
translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg
|
101
|
-
pointer-events-auto
|
105
|
+
pointer-events-auto outline-none
|
102
106
|
HEREDOC
|
103
107
|
)
|
104
108
|
|
@@ -117,16 +121,14 @@ module ShadcnPhlexcomponents
|
|
117
121
|
labelledby: "#{@aria_id}-title",
|
118
122
|
},
|
119
123
|
data: {
|
120
|
-
dialog_target: "content",
|
121
124
|
state: "closed",
|
122
|
-
|
125
|
+
dialog_target: "content"
|
123
126
|
},
|
124
127
|
}
|
125
128
|
end
|
126
129
|
|
127
130
|
def view_template(&)
|
128
|
-
|
129
|
-
div(class: "#{@class} hidden", **@attributes) do
|
131
|
+
div(style: { display: "none" }, **@attributes) do
|
130
132
|
yield
|
131
133
|
|
132
134
|
button(
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module ShadcnPhlexcomponents
|
4
4
|
class DropdownMenu < Base
|
5
|
-
class_variants(base: "inline-
|
5
|
+
class_variants(base: "inline-flex max-w-fit")
|
6
6
|
|
7
7
|
def initialize(open: false, **attributes)
|
8
8
|
@aria_id = "dropdown-menu-#{SecureRandom.hex(5)}"
|
@@ -93,9 +93,9 @@ module ShadcnPhlexcomponents
|
|
93
93
|
dropdown_menu_target: "trigger",
|
94
94
|
action: <<~HEREDOC,
|
95
95
|
click->dropdown-menu#toggle
|
96
|
-
keydown.space->dropdown-menu#open
|
97
|
-
keydown.enter->dropdown-menu#open
|
98
96
|
keydown.down->dropdown-menu#open:prevent
|
97
|
+
keydown.space->dropdown-menu#open:prevent
|
98
|
+
keydown.enter->dropdown-menu#open:prevent
|
99
99
|
HEREDOC
|
100
100
|
},
|
101
101
|
}
|
@@ -123,7 +123,8 @@ module ShadcnPhlexcomponents
|
|
123
123
|
|
124
124
|
def view_template(&)
|
125
125
|
div(
|
126
|
-
|
126
|
+
style: { display: "none" },
|
127
|
+
class: "fixed top-0 left-0 w-max z-50",
|
127
128
|
data: { dropdown_menu_target: "contentContainer" },
|
128
129
|
) do
|
129
130
|
div(**@attributes, &)
|
@@ -125,7 +125,8 @@ module ShadcnPhlexcomponents
|
|
125
125
|
|
126
126
|
def view_template(&)
|
127
127
|
div(
|
128
|
-
|
128
|
+
style: { display: "none" },
|
129
|
+
class: "fixed top-0 left-0 w-max z-50",
|
129
130
|
data: { dropdown_menu_sub_target: "contentContainer" },
|
130
131
|
) do
|
131
132
|
div(**@attributes, &)
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class FormCombobox < Base
|
5
|
+
include FormHelpers
|
6
|
+
|
7
|
+
def initialize(
|
8
|
+
method = nil,
|
9
|
+
model: false,
|
10
|
+
object_name: nil,
|
11
|
+
collection: [],
|
12
|
+
value_method: nil,
|
13
|
+
text_method: nil,
|
14
|
+
value: nil,
|
15
|
+
name: nil,
|
16
|
+
id: nil,
|
17
|
+
label: nil,
|
18
|
+
error: nil,
|
19
|
+
hint: nil,
|
20
|
+
disabled_items: nil,
|
21
|
+
**attributes
|
22
|
+
)
|
23
|
+
@method = method
|
24
|
+
@model = model
|
25
|
+
@object_name = object_name
|
26
|
+
|
27
|
+
@collection = if collection.first&.is_a?(Hash)
|
28
|
+
convert_collection_hash_to_struct(collection, value_method: value_method, text_method: text_method)
|
29
|
+
else
|
30
|
+
collection
|
31
|
+
end
|
32
|
+
|
33
|
+
@value_method = value_method
|
34
|
+
@text_method = text_method
|
35
|
+
@value = default_value(value, method)
|
36
|
+
@name = name
|
37
|
+
@id = id
|
38
|
+
@label = label
|
39
|
+
@error = default_error(error, method)
|
40
|
+
@hint = hint
|
41
|
+
@disabled_items = disabled_items
|
42
|
+
@aria_id = "form-field-#{SecureRandom.hex(5)}"
|
43
|
+
super(**attributes)
|
44
|
+
end
|
45
|
+
|
46
|
+
def view_template(&)
|
47
|
+
vanish(&)
|
48
|
+
|
49
|
+
@id ||= field_id(@object_name, @method)
|
50
|
+
@name ||= field_name(@object_name, @method)
|
51
|
+
|
52
|
+
div(class: "space-y-2", data: label_and_hint_container_attributes) do
|
53
|
+
render_label(&)
|
54
|
+
|
55
|
+
Combobox(id: @id, name: @name, value: @value, aria: aria_attributes, **@attributes) do |c|
|
56
|
+
c.items(@collection, value_method: @value_method, text_method: @text_method, disabled_items: @disabled_items)
|
57
|
+
end
|
58
|
+
|
59
|
+
render_hint(&)
|
60
|
+
render_error
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|