shadcn_phlexcomponents 0.1.11 → 0.1.16

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 (106) hide show
  1. checksums.yaml +4 -4
  2. data/app/javascript/controllers/accordion_controller.js +107 -0
  3. data/app/javascript/controllers/alert_dialog_controller.js +7 -0
  4. data/app/javascript/controllers/avatar_controller.js +14 -0
  5. data/app/javascript/controllers/checkbox_controller.js +29 -0
  6. data/app/javascript/controllers/collapsible_controller.js +39 -0
  7. data/app/javascript/controllers/combobox_controller.js +278 -0
  8. data/app/javascript/controllers/command_controller.js +207 -0
  9. data/app/javascript/controllers/date_picker_controller.js +258 -0
  10. data/app/javascript/controllers/date_range_picker_controller.js +200 -0
  11. data/app/javascript/controllers/dialog_controller.js +83 -0
  12. data/app/javascript/controllers/dropdown_menu_controller.js +238 -0
  13. data/app/javascript/controllers/dropdown_menu_sub_controller.js +118 -0
  14. data/app/javascript/controllers/form_field_controller.js +20 -0
  15. data/app/javascript/controllers/hover_card_controller.js +73 -0
  16. data/app/javascript/controllers/loading_button_controller.js +14 -0
  17. data/app/javascript/controllers/popover_controller.js +90 -0
  18. data/app/javascript/controllers/progress_controller.js +14 -0
  19. data/app/javascript/controllers/radio_group_controller.js +80 -0
  20. data/app/javascript/controllers/select_controller.js +265 -0
  21. data/app/javascript/controllers/sidebar_controller.js +29 -0
  22. data/app/javascript/controllers/sidebar_trigger_controller.js +15 -0
  23. data/app/javascript/controllers/slider_controller.js +82 -0
  24. data/app/javascript/controllers/switch_controller.js +26 -0
  25. data/app/javascript/controllers/tabs_controller.js +66 -0
  26. data/app/javascript/controllers/theme_switcher_controller.js +32 -0
  27. data/app/javascript/controllers/toast_container_controller.js +48 -0
  28. data/app/javascript/controllers/toast_controller.js +22 -0
  29. data/app/javascript/controllers/toggle_controller.js +20 -0
  30. data/app/javascript/controllers/toggle_group_controller.js +20 -0
  31. data/app/javascript/controllers/tooltip_controller.js +79 -0
  32. data/app/javascript/shadcn_phlexcomponents.js +60 -0
  33. data/app/javascript/utils/command.js +448 -0
  34. data/app/javascript/utils/floating_ui.js +160 -0
  35. data/app/javascript/utils/index.js +288 -0
  36. data/app/stylesheets/date_picker.css +118 -0
  37. data/app/typescript/controllers/accordion_controller.ts +136 -0
  38. data/app/typescript/controllers/alert_dialog_controller.ts +12 -0
  39. data/app/{javascript → typescript}/controllers/avatar_controller.ts +7 -2
  40. data/app/{javascript → typescript}/controllers/checkbox_controller.ts +11 -4
  41. data/app/{javascript → typescript}/controllers/collapsible_controller.ts +12 -5
  42. data/app/typescript/controllers/combobox_controller.ts +376 -0
  43. data/app/typescript/controllers/command_controller.ts +301 -0
  44. data/app/{javascript → typescript}/controllers/date_picker_controller.ts +185 -125
  45. data/app/{javascript → typescript}/controllers/date_range_picker_controller.ts +89 -79
  46. data/app/{javascript → typescript}/controllers/dialog_controller.ts +59 -57
  47. data/app/typescript/controllers/dropdown_menu_controller.ts +309 -0
  48. data/app/{javascript → typescript}/controllers/dropdown_menu_sub_controller.ts +31 -29
  49. data/app/{javascript → typescript}/controllers/form_field_controller.ts +6 -1
  50. data/app/{javascript → typescript}/controllers/hover_card_controller.ts +36 -26
  51. data/app/{javascript → typescript}/controllers/loading_button_controller.ts +6 -1
  52. data/app/{javascript → typescript}/controllers/popover_controller.ts +42 -65
  53. data/app/{javascript → typescript}/controllers/progress_controller.ts +9 -3
  54. data/app/{javascript → typescript}/controllers/radio_group_controller.ts +16 -9
  55. data/app/typescript/controllers/select_controller.ts +341 -0
  56. data/app/{javascript → typescript}/controllers/slider_controller.ts +23 -16
  57. data/app/{javascript → typescript}/controllers/switch_controller.ts +11 -4
  58. data/app/{javascript → typescript}/controllers/tabs_controller.ts +26 -18
  59. data/app/{javascript → typescript}/controllers/theme_switcher_controller.ts +6 -1
  60. data/app/{javascript → typescript}/controllers/toast_container_controller.ts +6 -1
  61. data/app/{javascript → typescript}/controllers/toast_controller.ts +7 -1
  62. data/app/typescript/controllers/toggle_controller.ts +28 -0
  63. data/app/typescript/controllers/toggle_group_controller.ts +28 -0
  64. data/app/{javascript → typescript}/controllers/tooltip_controller.ts +43 -31
  65. data/app/typescript/shadcn_phlexcomponents.ts +61 -0
  66. data/app/typescript/utils/command.ts +544 -0
  67. data/app/typescript/utils/floating_ui.ts +196 -0
  68. data/app/typescript/utils/index.ts +424 -0
  69. data/lib/install/install_shadcn_phlexcomponents.rb +10 -3
  70. data/lib/shadcn_phlexcomponents/alias.rb +3 -0
  71. data/lib/shadcn_phlexcomponents/components/accordion.rb +2 -1
  72. data/lib/shadcn_phlexcomponents/components/alert_dialog.rb +18 -15
  73. data/lib/shadcn_phlexcomponents/components/base.rb +14 -0
  74. data/lib/shadcn_phlexcomponents/components/collapsible.rb +1 -2
  75. data/lib/shadcn_phlexcomponents/components/combobox.rb +87 -57
  76. data/lib/shadcn_phlexcomponents/components/command.rb +77 -47
  77. data/lib/shadcn_phlexcomponents/components/date_picker.rb +25 -81
  78. data/lib/shadcn_phlexcomponents/components/date_range_picker.rb +21 -4
  79. data/lib/shadcn_phlexcomponents/components/dialog.rb +14 -12
  80. data/lib/shadcn_phlexcomponents/components/dropdown_menu.rb +5 -4
  81. data/lib/shadcn_phlexcomponents/components/dropdown_menu_sub.rb +2 -1
  82. data/lib/shadcn_phlexcomponents/components/form/form_combobox.rb +64 -0
  83. data/lib/shadcn_phlexcomponents/components/form.rb +14 -0
  84. data/lib/shadcn_phlexcomponents/components/hover_card.rb +3 -2
  85. data/lib/shadcn_phlexcomponents/components/popover.rb +3 -3
  86. data/lib/shadcn_phlexcomponents/components/select.rb +10 -25
  87. data/lib/shadcn_phlexcomponents/components/sheet.rb +15 -11
  88. data/lib/shadcn_phlexcomponents/components/table.rb +1 -1
  89. data/lib/shadcn_phlexcomponents/components/tabs.rb +1 -1
  90. data/lib/shadcn_phlexcomponents/components/toast_container.rb +1 -1
  91. data/lib/shadcn_phlexcomponents/components/toggle.rb +54 -0
  92. data/lib/shadcn_phlexcomponents/components/tooltip.rb +3 -2
  93. data/lib/shadcn_phlexcomponents/engine.rb +1 -5
  94. data/lib/shadcn_phlexcomponents/version.rb +1 -1
  95. metadata +71 -32
  96. data/app/javascript/controllers/accordion_controller.ts +0 -133
  97. data/app/javascript/controllers/combobox_controller.ts +0 -145
  98. data/app/javascript/controllers/command_controller.ts +0 -129
  99. data/app/javascript/controllers/command_root_controller.ts +0 -355
  100. data/app/javascript/controllers/dropdown_menu_controller.ts +0 -133
  101. data/app/javascript/controllers/dropdown_menu_root_controller.ts +0 -234
  102. data/app/javascript/controllers/select_controller.ts +0 -200
  103. data/app/javascript/shadcn_phlexcomponents.ts +0 -57
  104. data/app/javascript/utils.ts +0 -437
  105. /data/app/{javascript → typescript}/controllers/sidebar_controller.ts +0 -0
  106. /data/app/{javascript → typescript}/controllers/sidebar_trigger_controller.ts +0 -0
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ShadcnPhlexcomponents
4
4
  class AlertDialog < Base
5
- class_variants(base: "inline-block max-w-fit")
5
+ class_variants(base: "inline-flex max-w-fit")
6
6
 
7
7
  def initialize(open: false, **attributes)
8
8
  @open = open
@@ -49,14 +49,18 @@ module ShadcnPhlexcomponents
49
49
  def default_attributes
50
50
  {
51
51
  data: {
52
- controller: "dialog",
53
- dialog_is_open_value: @open.to_s,
54
- },
55
- }
52
+ controller: "alert-dialog",
53
+ alert_dialog_is_open_value: @open.to_s
54
+ }
55
+ }
56
56
  end
57
57
 
58
58
  def view_template(&)
59
- div(**@attributes, &)
59
+ div(**@attributes) do
60
+ overlay("alert-dialog")
61
+
62
+ yield
63
+ end
60
64
  end
61
65
  end
62
66
 
@@ -75,10 +79,10 @@ module ShadcnPhlexcomponents
75
79
  expanded: "false",
76
80
  controls: "#{@aria_id}-content",
77
81
  },
78
- data: {
79
- action: "click->dialog#open",
80
- dialog_target: "trigger",
82
+ data: {
81
83
  as_child: @as_child.to_s,
84
+ alert_dialog_target: "trigger",
85
+ action: "click->alert-dialog#open"
82
86
  },
83
87
  }
84
88
  end
@@ -106,7 +110,7 @@ module ShadcnPhlexcomponents
106
110
  data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95
107
111
  data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)]
108
112
  translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg
109
- pointer-events-auto
113
+ pointer-events-auto outline-none
110
114
  HEREDOC
111
115
  )
112
116
 
@@ -126,14 +130,13 @@ module ShadcnPhlexcomponents
126
130
  },
127
131
  data: {
128
132
  state: "closed",
129
- dialog_target: "content",
133
+ alert_dialog_target: "content"
130
134
  },
131
135
  }
132
136
  end
133
137
 
134
138
  def view_template(&)
135
- @class = @attributes.delete(:class)
136
- div(class: "#{@class} hidden", **@attributes, &)
139
+ div(style: { display: "none" }, **@attributes, &)
137
140
  end
138
141
  end
139
142
 
@@ -201,7 +204,7 @@ module ShadcnPhlexcomponents
201
204
  def default_attributes
202
205
  {
203
206
  data: {
204
- action: "click->dialog#close",
207
+ action: "click->alert-dialog#close",
205
208
  },
206
209
  }
207
210
  end
@@ -222,7 +225,7 @@ module ShadcnPhlexcomponents
222
225
  def default_attributes
223
226
  {
224
227
  data: {
225
- action: "click->dialog#close",
228
+ action: "click->alert-dialog#close",
226
229
  },
227
230
  }
228
231
  end
@@ -141,5 +141,19 @@ module ShadcnPhlexcomponents
141
141
  disabled
142
142
  end
143
143
  end
144
+
145
+ def overlay(component)
146
+ div(
147
+ style: { display: "none" },
148
+ class: "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50 pointer-events-auto",
149
+ aria: {
150
+ hidden: true,
151
+ },
152
+ data: {
153
+ state: "closed",
154
+ "#{component}-target" => "overlay"
155
+ }
156
+ )
157
+ end
144
158
  end
145
159
  end
@@ -84,8 +84,7 @@ module ShadcnPhlexcomponents
84
84
  end
85
85
 
86
86
  def view_template(&)
87
- @class = @attributes.delete(:class)
88
- div(class: "#{@class} hidden", **@attributes, &)
87
+ div(style: { display: "none" }, **@attributes, &)
89
88
  end
90
89
  end
91
90
  end
@@ -9,18 +9,24 @@ module ShadcnPhlexcomponents
9
9
  name: nil,
10
10
  value: nil,
11
11
  placeholder: nil,
12
- dir: "ltr",
13
12
  include_blank: false,
14
13
  disabled: false,
14
+ search_path: nil,
15
+ search_error_text: "Something went wrong, please try again.",
16
+ search_empty_text: "No results found",
17
+ search_placeholder_text: "Search...",
15
18
  **attributes
16
19
  )
17
20
  @id = id
18
21
  @name = name
19
22
  @value = value
20
23
  @placeholder = placeholder
21
- @dir = dir
22
24
  @include_blank = include_blank
23
25
  @disabled = disabled
26
+ @search_path = search_path
27
+ @search_error_text = search_error_text
28
+ @search_empty_text = search_empty_text
29
+ @search_placeholder_text = search_placeholder_text
24
30
  @aria_id = "combobox-#{SecureRandom.hex(5)}"
25
31
  super(**attributes)
26
32
  end
@@ -29,7 +35,6 @@ module ShadcnPhlexcomponents
29
35
  ComboboxTrigger(
30
36
  id: @id,
31
37
  aria_id: @aria_id,
32
- dir: @dir,
33
38
  value: @value,
34
39
  placeholder: @placeholder,
35
40
  disabled: @disabled,
@@ -39,7 +44,13 @@ module ShadcnPhlexcomponents
39
44
 
40
45
  def content(**attributes, &)
41
46
  ComboboxContent(
42
- aria_id: @aria_id, dir: @dir, include_blank: @include_blank, **attributes, &
47
+ include_blank: @include_blank,
48
+ search_error_text: @search_error_text,
49
+ search_empty_text: @search_empty_text,
50
+ search_placeholder_text: @search_placeholder_text,
51
+ aria_id: @aria_id,
52
+ **attributes,
53
+ &
43
54
  )
44
55
  end
45
56
 
@@ -69,13 +80,18 @@ module ShadcnPhlexcomponents
69
80
  ComboboxTrigger(
70
81
  id: @id,
71
82
  aria_id: @aria_id,
72
- dir: @dir,
73
83
  value: @value,
74
84
  placeholder: @placeholder,
75
85
  disabled: @disabled,
76
86
  )
77
87
 
78
- ComboboxContent(aria_id: @aria_id, dir: @dir, include_blank: @include_blank) do
88
+ ComboboxContent(
89
+ aria_id: @aria_id,
90
+ include_blank: @include_blank,
91
+ search_error_text: @search_error_text,
92
+ search_empty_text: @search_empty_text,
93
+ search_placeholder_text: @search_placeholder_text
94
+ ) do
79
95
  collection.each do |item|
80
96
  value = item.public_send(value_method)
81
97
  text = item.public_send(text_method)
@@ -103,6 +119,7 @@ module ShadcnPhlexcomponents
103
119
  data: {
104
120
  aria_id: @aria_id,
105
121
  controller: "combobox",
122
+ search_path: @search_path,
106
123
  combobox_selected_value: @value,
107
124
  },
108
125
  }
@@ -117,25 +134,22 @@ module ShadcnPhlexcomponents
117
134
  aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex items-center
118
135
  justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs
119
136
  transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50
120
- data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[combobox-target=triggerText]:line-clamp-1#{" "}
121
- *:data-[combobox-target=triggerText]:flex *:data-[combobox-target=triggerText]:items-center *:data-[combobox-target=triggerText]:gap-2
122
- [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4
123
- data-[placeholder]:data-[has-value=false]:text-muted-foreground w-full
137
+ h-9 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4
138
+ data-[placeholder]:data-[has-value=false]:text-muted-foreground w-full disabled:dark:hover:bg-input/30
124
139
  HEREDOC
125
140
  )
126
141
 
127
- def initialize(id: nil, value: nil, placeholder: nil, dir: "ltr", aria_id: nil, **attributes)
142
+ def initialize(id: nil, value: nil, placeholder: nil, aria_id: nil, **attributes)
128
143
  @id = id
129
144
  @value = value
130
145
  @placeholder = placeholder
131
- @dir = dir
132
146
  @aria_id = aria_id
133
147
  super(**attributes)
134
148
  end
135
149
 
136
150
  def view_template
137
151
  button(**@attributes) do
138
- span(class: "pointer-events-none", data: { combobox_target: "triggerText" }) do
152
+ span(class: "pointer-events-none line-clamp-1 flex items-center gap-2", data: { combobox_target: "triggerText" }) do
139
153
  @value || @placeholder
140
154
  end
141
155
 
@@ -147,7 +161,6 @@ module ShadcnPhlexcomponents
147
161
  {
148
162
  type: "button",
149
163
  id: @id,
150
- dir: @dir,
151
164
  role: "combobox",
152
165
  aria: {
153
166
  autocomplete: "none",
@@ -159,8 +172,6 @@ module ShadcnPhlexcomponents
159
172
  has_value: @value.present?.to_s,
160
173
  action: <<~HEREDOC,
161
174
  click->combobox#toggle
162
- keydown.space->combobox#open
163
- keydown.enter->combobox#open
164
175
  keydown.down->combobox#open:prevent
165
176
  HEREDOC
166
177
  combobox_target: "trigger",
@@ -176,27 +187,44 @@ module ShadcnPhlexcomponents
176
187
  data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95
177
188
  data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2
178
189
  data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50
179
- max-h-(--radix-popper-available-height) min-w-[8rem] origin-(--radix-popper-transform-origin)
180
- overflow-x-hidden overflow-y-auto rounded-md border shadow-md pointer-events-auto outline-none
190
+ min-w-[8rem] origin-(--radix-popper-transform-origin)
191
+ rounded-md border shadow-md pointer-events-auto outline-none
181
192
  HEREDOC
182
193
  )
183
194
 
184
- def initialize(include_blank: false, dir: "ltr", side: :bottom, align: :center, aria_id: nil, search_placeholder: "Search...", **attributes)
195
+ def initialize(
196
+ include_blank: false,
197
+ side: :bottom,
198
+ align: :center,
199
+ aria_id: nil,
200
+ search_error_text: nil,
201
+ search_empty_text: nil,
202
+ search_placeholder_text: nil,
203
+ **attributes
204
+ )
185
205
  @include_blank = include_blank
186
- @dir = dir
187
206
  @side = side
188
207
  @align = align
189
- @search_placeholder = search_placeholder
208
+ @search_error_text = search_error_text
209
+ @search_empty_text = search_empty_text
210
+ @search_placeholder_text = search_placeholder_text
190
211
  @aria_id = aria_id
191
212
  super(**attributes)
192
213
  end
193
214
 
194
215
  def view_template(&)
195
216
  div(
196
- class: "hidden fixed top-0 left-0 w-max z-50",
217
+ style: { display: "none" },
218
+ class: "fixed top-0 left-0 w-max z-50",
197
219
  data: { combobox_target: "contentContainer" },
198
220
  ) do
199
221
  div(**@attributes) do
222
+ template do
223
+ ComboboxGroup do
224
+ ComboboxLabel { "" }
225
+ end
226
+ end
227
+
200
228
  label(
201
229
  class: "sr-only",
202
230
  id: "#{@aria_id}-search-label",
@@ -224,19 +252,29 @@ module ShadcnPhlexcomponents
224
252
  },
225
253
  data: {
226
254
  combobox_target: "searchInput",
227
- action: "input->combobox#search",
255
+ action: "keydown->combobox#inputKeydown input->combobox#search",
228
256
  },
229
257
  )
230
258
  end
231
259
 
232
- div(class: "p-1 max-h-80 overflow-y-auto", id: "#{@aria_id}-list", data: { combobox_target: "list" }) do
233
- if @include_blank
234
- ComboboxItem(aria_id: @aria_id, value: "", class: "h-8", hide_icon: true) do
235
- @include_blank.is_a?(String) ? @include_blank : ""
260
+ div(class: "p-1 max-h-80 overflow-y-auto", data: { combobox_target: "listContainer"}) do
261
+ ComboboxText(target: "empty") { @search_empty_text }
262
+ ComboboxText(target: "error") { @search_error_text }
263
+ ComboboxText(target: "loading") do
264
+ div(class: "flex justify-center", aria: { label: "Loading" }) do
265
+ icon("loader-circle", class: "animate-spin")
236
266
  end
237
267
  end
238
268
 
239
- div(data: { combobox_target: "results" }, &)
269
+ div(id: "#{@aria_id}-list", data: { combobox_target: "list" }) do
270
+ if @include_blank
271
+ ComboboxItem(aria_id: @aria_id, value: "", class: "h-8") do
272
+ @include_blank.is_a?(String) ? @include_blank : ""
273
+ end
274
+ end
275
+
276
+ yield
277
+ end
240
278
  end
241
279
  end
242
280
  end
@@ -245,7 +283,6 @@ module ShadcnPhlexcomponents
245
283
  def default_attributes
246
284
  {
247
285
  id: "#{@aria_id}-content",
248
- dir: @dir,
249
286
  tabindex: -1,
250
287
  role: "listbox",
251
288
  aria: {
@@ -261,7 +298,7 @@ module ShadcnPhlexcomponents
261
298
  combobox:click:outside->combobox#clickOutside
262
299
  keydown.up->combobox#highlightItem:prevent
263
300
  keydown.down->combobox#highlightItem:prevent
264
- keydown.enter->combobox#select
301
+ keydown.enter->combobox#select:prevent
265
302
  HEREDOC
266
303
  },
267
304
  }
@@ -280,14 +317,6 @@ module ShadcnPhlexcomponents
280
317
  def view_template(&)
281
318
  div(**@attributes, &)
282
319
  end
283
-
284
- def default_attributes
285
- {
286
- data: {
287
- combobox_target: "label",
288
- },
289
- }
290
- end
291
320
  end
292
321
 
293
322
  class ComboboxItem < Base
@@ -365,34 +394,35 @@ module ShadcnPhlexcomponents
365
394
  end
366
395
  end
367
396
 
368
- class ComboboxSeparator < Base
369
- class_variants(base: "bg-border pointer-events-none -mx-1 my-1 h-px")
370
-
371
- def view_template(&)
372
- div(**@attributes, &)
373
- end
374
-
375
- def default_attributes
376
- { aria: { hidden: "true" } }
377
- end
378
- end
379
-
380
- class ComboboxEmpty < Base
397
+ class ComboboxText < Base
381
398
  class_variants(base: "py-6 text-center text-sm hidden")
399
+
400
+ def initialize(target:, **attributes)
401
+ @target = target
402
+ super(**attributes)
403
+ end
382
404
 
383
405
  def default_attributes
384
406
  {
385
407
  role: "presentation",
386
- data: { combobox_target: "empty" },
408
+ data: { combobox_target: @target },
387
409
  }
388
410
  end
389
411
 
390
412
  def view_template(&)
391
- if block_given?
392
- div(**@attributes, &)
393
- else
394
- div(**@attributes) { "No results found" }
395
- end
413
+ div(**@attributes, &)
414
+ end
415
+ end
416
+
417
+ class ComboboxSeparator < Base
418
+ class_variants(base: "bg-border pointer-events-none -mx-1 my-1 h-px")
419
+
420
+ def view_template(&)
421
+ div(**@attributes, &)
422
+ end
423
+
424
+ def default_attributes
425
+ { aria: { hidden: "true" } }
396
426
  end
397
427
  end
398
428
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ShadcnPhlexcomponents
4
4
  class Command < Base
5
- class_variants(base: "inline-block max-w-fit")
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(modifier_key: nil, shortcut_key: nil, search_path: nil, open: false, **attributes)
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(aria_id: @aria_id, **attributes, &)
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
- command_is_open_value: @open.to_s,
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
- as_child: @as_child.to_s,
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(search_placeholder: "Search...", aria_id: nil, **attributes)
131
- @search_placeholder = search_placeholder
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#close
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
- @class = @attributes.delete(:class)
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") { @search_placeholder }
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
- ) { @search_placeholder }
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: @search_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", id: "#{@aria_id}-list", data: { command_target: "list" }) do
202
- div(data: { command_target: "results" }, &)
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 p-3 pb-1 text-xs font-medium")
292
+ class_variants(base: "text-muted-foreground text-xs px-3 pb-1 text-xs font-medium")
255
293
 
256
- def initialize(aria_id: nil, **attributes)
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:, **attributes)
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 CommandEmpty < Base
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: "empty" },
339
+ data: { command_target: @target },
306
340
  }
307
341
  end
308
342
 
309
343
  def view_template(&)
310
- if block_given?
311
- div(**@attributes, &)
312
- else
313
- div(**@attributes) { "No results found" }
314
- end
344
+ div(**@attributes, &)
315
345
  end
316
346
  end
317
347