shadcn_phlexcomponents 0.1.9 → 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.
Files changed (256) hide show
  1. checksums.yaml +4 -4
  2. data/app/javascript/controllers/accordion_controller.ts +136 -0
  3. data/app/javascript/controllers/alert_dialog_controller.ts +12 -0
  4. data/app/javascript/controllers/avatar_controller.ts +24 -0
  5. data/app/javascript/controllers/checkbox_controller.ts +41 -0
  6. data/app/javascript/controllers/collapsible_controller.ts +52 -0
  7. data/app/javascript/controllers/combobox_controller.ts +376 -0
  8. data/app/javascript/controllers/command_controller.ts +301 -0
  9. data/app/javascript/controllers/date_picker_controller.ts +334 -0
  10. data/app/javascript/controllers/date_range_picker_controller.ts +253 -0
  11. data/app/javascript/controllers/dialog_controller.ts +115 -0
  12. data/app/javascript/controllers/dropdown_menu_controller.ts +309 -0
  13. data/app/javascript/controllers/dropdown_menu_sub_controller.ts +152 -0
  14. data/app/javascript/controllers/form_field_controller.ts +27 -0
  15. data/app/javascript/controllers/hover_card_controller.ts +103 -0
  16. data/app/javascript/controllers/{loading_button_controller.js → loading_button_controller.ts} +7 -2
  17. data/app/javascript/controllers/popover_controller.ts +118 -0
  18. data/app/javascript/controllers/progress_controller.ts +23 -0
  19. data/app/javascript/controllers/radio_group_controller.ts +113 -0
  20. data/app/javascript/controllers/select_controller.ts +341 -0
  21. data/app/javascript/controllers/{sidebar_controller.js → sidebar_controller.ts} +6 -2
  22. data/app/javascript/controllers/sidebar_trigger_controller.ts +21 -0
  23. data/app/javascript/controllers/slider_controller.ts +114 -0
  24. data/app/javascript/controllers/switch_controller.ts +37 -0
  25. data/app/javascript/controllers/tabs_controller.ts +87 -0
  26. data/app/javascript/controllers/theme_switcher_controller.ts +40 -0
  27. data/app/javascript/controllers/toast_container_controller.ts +67 -0
  28. data/app/javascript/controllers/toast_controller.ts +34 -0
  29. data/app/javascript/controllers/toggle_controller.ts +28 -0
  30. data/app/javascript/controllers/toggle_group_controller.ts +28 -0
  31. data/app/javascript/controllers/tooltip_controller.ts +110 -0
  32. data/app/javascript/shadcn_phlexcomponents.ts +61 -0
  33. data/app/javascript/utils/command.ts +544 -0
  34. data/app/javascript/utils/floating_ui.ts +196 -0
  35. data/app/javascript/utils/index.ts +417 -0
  36. data/app/stylesheets/date_picker.css +81 -101
  37. data/app/stylesheets/nouislider.css +173 -0
  38. data/app/stylesheets/tw-animate.css +486 -0
  39. data/lib/install/install_shadcn_phlexcomponents.rb +16 -3
  40. data/lib/shadcn_phlexcomponents/alias.rb +6 -1
  41. data/lib/shadcn_phlexcomponents/components/accordion.rb +130 -0
  42. data/lib/shadcn_phlexcomponents/components/alert.rb +59 -0
  43. data/lib/shadcn_phlexcomponents/components/alert_dialog.rb +279 -0
  44. data/lib/shadcn_phlexcomponents/components/{aspect_ratio/aspect_ratio.rb → aspect_ratio.rb} +2 -2
  45. data/lib/shadcn_phlexcomponents/components/avatar.rb +63 -0
  46. data/lib/shadcn_phlexcomponents/components/badge.rb +35 -0
  47. data/lib/shadcn_phlexcomponents/components/base.rb +48 -7
  48. data/lib/shadcn_phlexcomponents/components/breadcrumb.rb +150 -0
  49. data/lib/shadcn_phlexcomponents/components/button.rb +49 -0
  50. data/lib/shadcn_phlexcomponents/components/card.rb +88 -0
  51. data/lib/shadcn_phlexcomponents/components/{checkbox/checkbox.rb → checkbox.rb} +18 -14
  52. data/lib/shadcn_phlexcomponents/components/{checkbox_group/checkbox_group.rb → checkbox_group.rb} +7 -8
  53. data/lib/shadcn_phlexcomponents/components/collapsible.rb +90 -0
  54. data/lib/shadcn_phlexcomponents/components/combobox.rb +428 -0
  55. data/lib/shadcn_phlexcomponents/components/command.rb +381 -0
  56. data/lib/shadcn_phlexcomponents/components/date_picker.rb +208 -0
  57. data/lib/shadcn_phlexcomponents/components/date_range_picker.rb +143 -0
  58. data/lib/shadcn_phlexcomponents/components/dialog.rb +236 -0
  59. data/lib/shadcn_phlexcomponents/components/dropdown_menu.rb +283 -0
  60. data/lib/shadcn_phlexcomponents/components/dropdown_menu_sub.rb +136 -0
  61. data/lib/shadcn_phlexcomponents/components/form/form_checkbox.rb +6 -7
  62. data/lib/shadcn_phlexcomponents/components/form/form_checkbox_group.rb +2 -2
  63. data/lib/shadcn_phlexcomponents/components/form/form_combobox.rb +64 -0
  64. data/lib/shadcn_phlexcomponents/components/form/form_date_picker.rb +3 -4
  65. data/lib/shadcn_phlexcomponents/components/form/form_date_range_picker.rb +27 -41
  66. data/lib/shadcn_phlexcomponents/components/form/form_error.rb +1 -1
  67. data/lib/shadcn_phlexcomponents/components/form/form_helpers.rb +43 -8
  68. data/lib/shadcn_phlexcomponents/components/form/form_hint.rb +1 -1
  69. data/lib/shadcn_phlexcomponents/components/form/form_input.rb +3 -4
  70. data/lib/shadcn_phlexcomponents/components/form/form_radio_group.rb +4 -5
  71. data/lib/shadcn_phlexcomponents/components/form/form_select.rb +3 -4
  72. data/lib/shadcn_phlexcomponents/components/form/form_slider.rb +91 -0
  73. data/lib/shadcn_phlexcomponents/components/form/form_switch.rb +7 -6
  74. data/lib/shadcn_phlexcomponents/components/form/form_textarea.rb +3 -4
  75. data/lib/shadcn_phlexcomponents/components/{form/form.rb → form.rb} +36 -4
  76. data/lib/shadcn_phlexcomponents/components/hover_card.rb +111 -0
  77. data/lib/shadcn_phlexcomponents/components/input.rb +31 -0
  78. data/lib/shadcn_phlexcomponents/components/label.rb +16 -0
  79. data/lib/shadcn_phlexcomponents/components/{link/link.rb → link.rb} +10 -3
  80. data/lib/shadcn_phlexcomponents/components/{loading_button/loading_button.rb → loading_button.rb} +9 -2
  81. data/lib/shadcn_phlexcomponents/components/pagination.rb +166 -0
  82. data/lib/shadcn_phlexcomponents/components/popover.rb +116 -0
  83. data/lib/shadcn_phlexcomponents/components/{progress/progress.rb → progress.rb} +4 -4
  84. data/lib/shadcn_phlexcomponents/components/radio_group.rb +155 -0
  85. data/lib/shadcn_phlexcomponents/components/select.rb +406 -0
  86. data/lib/shadcn_phlexcomponents/components/{separator/separator.rb → separator.rb} +9 -8
  87. data/lib/shadcn_phlexcomponents/components/sheet.rb +243 -0
  88. data/lib/shadcn_phlexcomponents/components/{skeleton/skeleton.rb → skeleton.rb} +1 -1
  89. data/lib/shadcn_phlexcomponents/components/slider.rb +72 -0
  90. data/lib/shadcn_phlexcomponents/components/switch.rb +75 -0
  91. data/lib/shadcn_phlexcomponents/components/table.rb +140 -0
  92. data/lib/shadcn_phlexcomponents/components/tabs.rb +135 -0
  93. data/lib/shadcn_phlexcomponents/components/textarea.rb +24 -0
  94. data/lib/shadcn_phlexcomponents/components/toast.rb +153 -0
  95. data/lib/shadcn_phlexcomponents/components/{toast/toast_container.rb → toast_container.rb} +23 -4
  96. data/lib/shadcn_phlexcomponents/components/toggle.rb +54 -0
  97. data/lib/shadcn_phlexcomponents/components/tooltip.rb +132 -0
  98. data/lib/shadcn_phlexcomponents/engine.rb +1 -5
  99. data/lib/shadcn_phlexcomponents/initializers/shadcn_phlexcomponents.rb +25 -0
  100. data/lib/shadcn_phlexcomponents/version.rb +1 -1
  101. data/lib/tasks/install.rake +1 -1
  102. metadata +83 -167
  103. data/app/javascript/controllers/accordion_controller.js +0 -124
  104. data/app/javascript/controllers/alert_dialog_controller.js +0 -21
  105. data/app/javascript/controllers/avatar_controller.js +0 -15
  106. data/app/javascript/controllers/checkbox_controller.js +0 -28
  107. data/app/javascript/controllers/collapsible_controller.js +0 -35
  108. data/app/javascript/controllers/combobox_controller.js +0 -54
  109. data/app/javascript/controllers/date_picker_controller.js +0 -253
  110. data/app/javascript/controllers/date_range_picker_controller.js +0 -344
  111. data/app/javascript/controllers/dialog_controller.js +0 -114
  112. data/app/javascript/controllers/dropdown_menu_controller.js +0 -171
  113. data/app/javascript/controllers/form_field_controller.js +0 -24
  114. data/app/javascript/controllers/hover_card_controller.js +0 -21
  115. data/app/javascript/controllers/popover_controller.js +0 -113
  116. data/app/javascript/controllers/progress_controller.js +0 -14
  117. data/app/javascript/controllers/radio_group_controller.js +0 -90
  118. data/app/javascript/controllers/select_controller.js +0 -274
  119. data/app/javascript/controllers/sidebar_trigger_controller.js +0 -15
  120. data/app/javascript/controllers/switch_controller.js +0 -24
  121. data/app/javascript/controllers/tabs_controller.js +0 -73
  122. data/app/javascript/controllers/theme_switcher_controller.js +0 -32
  123. data/app/javascript/controllers/toast_container_controller.js +0 -22
  124. data/app/javascript/controllers/toast_controller.js +0 -45
  125. data/app/javascript/controllers/tooltip_controller.js +0 -40
  126. data/app/javascript/shadcn_phlexcomponents.js +0 -53
  127. data/app/javascript/utils.js +0 -184
  128. data/app/stylesheets/choices.css +0 -324
  129. data/app/stylesheets/tailwindcss-animate.css +0 -318
  130. data/lib/shadcn_phlexcomponents/components/accordion/accordion.rb +0 -38
  131. data/lib/shadcn_phlexcomponents/components/accordion/accordion_content.rb +0 -30
  132. data/lib/shadcn_phlexcomponents/components/accordion/accordion_item.rb +0 -26
  133. data/lib/shadcn_phlexcomponents/components/accordion/accordion_trigger.rb +0 -46
  134. data/lib/shadcn_phlexcomponents/components/alert/alert.rb +0 -40
  135. data/lib/shadcn_phlexcomponents/components/alert/alert_description.rb +0 -11
  136. data/lib/shadcn_phlexcomponents/components/alert/alert_title.rb +0 -11
  137. data/lib/shadcn_phlexcomponents/components/alert_dialog/alert_dialog.rb +0 -60
  138. data/lib/shadcn_phlexcomponents/components/alert_dialog/alert_dialog_action.rb +0 -22
  139. data/lib/shadcn_phlexcomponents/components/alert_dialog/alert_dialog_action_to.rb +0 -40
  140. data/lib/shadcn_phlexcomponents/components/alert_dialog/alert_dialog_cancel.rb +0 -22
  141. data/lib/shadcn_phlexcomponents/components/alert_dialog/alert_dialog_content.rb +0 -40
  142. data/lib/shadcn_phlexcomponents/components/alert_dialog/alert_dialog_description.rb +0 -22
  143. data/lib/shadcn_phlexcomponents/components/alert_dialog/alert_dialog_footer.rb +0 -11
  144. data/lib/shadcn_phlexcomponents/components/alert_dialog/alert_dialog_header.rb +0 -11
  145. data/lib/shadcn_phlexcomponents/components/alert_dialog/alert_dialog_title.rb +0 -22
  146. data/lib/shadcn_phlexcomponents/components/alert_dialog/alert_dialog_trigger.rb +0 -50
  147. data/lib/shadcn_phlexcomponents/components/avatar/avatar.rb +0 -31
  148. data/lib/shadcn_phlexcomponents/components/avatar/avatar_fallback.rb +0 -21
  149. data/lib/shadcn_phlexcomponents/components/avatar/avatar_image.rb +0 -19
  150. data/lib/shadcn_phlexcomponents/components/badge/badge.rb +0 -30
  151. data/lib/shadcn_phlexcomponents/components/breadcrumb/breadcrumb.rb +0 -53
  152. data/lib/shadcn_phlexcomponents/components/breadcrumb/breadcrumb_ellipsis.rb +0 -23
  153. data/lib/shadcn_phlexcomponents/components/breadcrumb/breadcrumb_item.rb +0 -11
  154. data/lib/shadcn_phlexcomponents/components/breadcrumb/breadcrumb_link.rb +0 -7
  155. data/lib/shadcn_phlexcomponents/components/breadcrumb/breadcrumb_page.rb +0 -21
  156. data/lib/shadcn_phlexcomponents/components/breadcrumb/breadcrumb_separator.rb +0 -26
  157. data/lib/shadcn_phlexcomponents/components/button/button.rb +0 -53
  158. data/lib/shadcn_phlexcomponents/components/card/card.rb +0 -31
  159. data/lib/shadcn_phlexcomponents/components/card/card_content.rb +0 -11
  160. data/lib/shadcn_phlexcomponents/components/card/card_description.rb +0 -11
  161. data/lib/shadcn_phlexcomponents/components/card/card_footer.rb +0 -11
  162. data/lib/shadcn_phlexcomponents/components/card/card_header.rb +0 -11
  163. data/lib/shadcn_phlexcomponents/components/card/card_title.rb +0 -11
  164. data/lib/shadcn_phlexcomponents/components/collapsible/collapsible.rb +0 -31
  165. data/lib/shadcn_phlexcomponents/components/collapsible/collapsible_content.rb +0 -24
  166. data/lib/shadcn_phlexcomponents/components/collapsible/collapsible_trigger.rb +0 -50
  167. data/lib/shadcn_phlexcomponents/components/date_picker/date_picker.rb +0 -87
  168. data/lib/shadcn_phlexcomponents/components/date_picker/date_picker_content.rb +0 -45
  169. data/lib/shadcn_phlexcomponents/components/date_picker/date_picker_trigger.rb +0 -64
  170. data/lib/shadcn_phlexcomponents/components/date_range_picker/date_range_picker.rb +0 -105
  171. data/lib/shadcn_phlexcomponents/components/date_range_picker/date_range_picker_content.rb +0 -9
  172. data/lib/shadcn_phlexcomponents/components/date_range_picker/date_range_picker_trigger.rb +0 -9
  173. data/lib/shadcn_phlexcomponents/components/dialog/dialog.rb +0 -52
  174. data/lib/shadcn_phlexcomponents/components/dialog/dialog_close.rb +0 -42
  175. data/lib/shadcn_phlexcomponents/components/dialog/dialog_content.rb +0 -54
  176. data/lib/shadcn_phlexcomponents/components/dialog/dialog_description.rb +0 -22
  177. data/lib/shadcn_phlexcomponents/components/dialog/dialog_footer.rb +0 -11
  178. data/lib/shadcn_phlexcomponents/components/dialog/dialog_header.rb +0 -11
  179. data/lib/shadcn_phlexcomponents/components/dialog/dialog_title.rb +0 -22
  180. data/lib/shadcn_phlexcomponents/components/dialog/dialog_trigger.rb +0 -50
  181. data/lib/shadcn_phlexcomponents/components/dropdown_menu/dropdown_menu.rb +0 -50
  182. data/lib/shadcn_phlexcomponents/components/dropdown_menu/dropdown_menu_content.rb +0 -52
  183. data/lib/shadcn_phlexcomponents/components/dropdown_menu/dropdown_menu_item.rb +0 -56
  184. data/lib/shadcn_phlexcomponents/components/dropdown_menu/dropdown_menu_item_to.rb +0 -28
  185. data/lib/shadcn_phlexcomponents/components/dropdown_menu/dropdown_menu_label.rb +0 -11
  186. data/lib/shadcn_phlexcomponents/components/dropdown_menu/dropdown_menu_separator.rb +0 -20
  187. data/lib/shadcn_phlexcomponents/components/dropdown_menu/dropdown_menu_trigger.rb +0 -57
  188. data/lib/shadcn_phlexcomponents/components/hover_card/hover_card.rb +0 -33
  189. data/lib/shadcn_phlexcomponents/components/hover_card/hover_card_content.rb +0 -32
  190. data/lib/shadcn_phlexcomponents/components/hover_card/hover_card_trigger.rb +0 -44
  191. data/lib/shadcn_phlexcomponents/components/input/input.rb +0 -32
  192. data/lib/shadcn_phlexcomponents/components/label/label.rb +0 -14
  193. data/lib/shadcn_phlexcomponents/components/pagination/pagination.rb +0 -38
  194. data/lib/shadcn_phlexcomponents/components/pagination/pagination_ellipsis.rb +0 -24
  195. data/lib/shadcn_phlexcomponents/components/pagination/pagination_link.rb +0 -34
  196. data/lib/shadcn_phlexcomponents/components/pagination/pagination_next.rb +0 -32
  197. data/lib/shadcn_phlexcomponents/components/pagination/pagination_previous.rb +0 -32
  198. data/lib/shadcn_phlexcomponents/components/popover/popover.rb +0 -34
  199. data/lib/shadcn_phlexcomponents/components/popover/popover_content.rb +0 -40
  200. data/lib/shadcn_phlexcomponents/components/popover/popover_trigger.rb +0 -50
  201. data/lib/shadcn_phlexcomponents/components/radio_group/radio_group.rb +0 -88
  202. data/lib/shadcn_phlexcomponents/components/radio_group/radio_group_item.rb +0 -66
  203. data/lib/shadcn_phlexcomponents/components/select/select.rb +0 -194
  204. data/lib/shadcn_phlexcomponents/components/select/select_content.rb +0 -64
  205. data/lib/shadcn_phlexcomponents/components/select/select_group.rb +0 -23
  206. data/lib/shadcn_phlexcomponents/components/select/select_item.rb +0 -59
  207. data/lib/shadcn_phlexcomponents/components/select/select_label.rb +0 -24
  208. data/lib/shadcn_phlexcomponents/components/select/select_trigger.rb +0 -56
  209. data/lib/shadcn_phlexcomponents/components/sheet/sheet.rb +0 -53
  210. data/lib/shadcn_phlexcomponents/components/sheet/sheet_close.rb +0 -42
  211. data/lib/shadcn_phlexcomponents/components/sheet/sheet_content.rb +0 -65
  212. data/lib/shadcn_phlexcomponents/components/sheet/sheet_description.rb +0 -22
  213. data/lib/shadcn_phlexcomponents/components/sheet/sheet_footer.rb +0 -11
  214. data/lib/shadcn_phlexcomponents/components/sheet/sheet_header.rb +0 -11
  215. data/lib/shadcn_phlexcomponents/components/sheet/sheet_title.rb +0 -22
  216. data/lib/shadcn_phlexcomponents/components/sheet/sheet_trigger.rb +0 -50
  217. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar.rb +0 -108
  218. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_container.rb +0 -11
  219. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_content.rb +0 -11
  220. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_footer.rb +0 -11
  221. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_group.rb +0 -11
  222. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_group_content.rb +0 -11
  223. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_group_label.rb +0 -16
  224. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_header.rb +0 -11
  225. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_inset.rb +0 -15
  226. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_menu.rb +0 -11
  227. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_menu_button.rb +0 -61
  228. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_menu_item.rb +0 -9
  229. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_menu_sub.rb +0 -14
  230. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_menu_sub_button.rb +0 -48
  231. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_menu_sub_item.rb +0 -9
  232. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_trigger.rb +0 -40
  233. data/lib/shadcn_phlexcomponents/components/switch/switch.rb +0 -66
  234. data/lib/shadcn_phlexcomponents/components/table/table.rb +0 -75
  235. data/lib/shadcn_phlexcomponents/components/table/table_body.rb +0 -11
  236. data/lib/shadcn_phlexcomponents/components/table/table_caption.rb +0 -11
  237. data/lib/shadcn_phlexcomponents/components/table/table_cell.rb +0 -11
  238. data/lib/shadcn_phlexcomponents/components/table/table_footer.rb +0 -11
  239. data/lib/shadcn_phlexcomponents/components/table/table_head.rb +0 -14
  240. data/lib/shadcn_phlexcomponents/components/table/table_header.rb +0 -11
  241. data/lib/shadcn_phlexcomponents/components/table/table_row.rb +0 -11
  242. data/lib/shadcn_phlexcomponents/components/tabs/tabs.rb +0 -38
  243. data/lib/shadcn_phlexcomponents/components/tabs/tabs_content.rb +0 -35
  244. data/lib/shadcn_phlexcomponents/components/tabs/tabs_list.rb +0 -23
  245. data/lib/shadcn_phlexcomponents/components/tabs/tabs_trigger.rb +0 -45
  246. data/lib/shadcn_phlexcomponents/components/textarea/textarea.rb +0 -29
  247. data/lib/shadcn_phlexcomponents/components/toast/toast.rb +0 -101
  248. data/lib/shadcn_phlexcomponents/components/toast/toast_action.rb +0 -39
  249. data/lib/shadcn_phlexcomponents/components/toast/toast_action_to.rb +0 -28
  250. data/lib/shadcn_phlexcomponents/components/toast/toast_content.rb +0 -11
  251. data/lib/shadcn_phlexcomponents/components/toast/toast_description.rb +0 -11
  252. data/lib/shadcn_phlexcomponents/components/toast/toast_title.rb +0 -11
  253. data/lib/shadcn_phlexcomponents/components/tooltip/tooltip.rb +0 -34
  254. data/lib/shadcn_phlexcomponents/components/tooltip/tooltip_content.rb +0 -39
  255. data/lib/shadcn_phlexcomponents/components/tooltip/tooltip_trigger.rb +0 -48
  256. /data/lib/shadcn_phlexcomponents/components/{theme_switcher/theme_switcher.rb → theme_switcher.rb} +0 -0
@@ -0,0 +1,152 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+ import { initFloatingUi } from '../utils/floating_ui'
3
+ import {
4
+ ON_OPEN_FOCUS_DELAY,
5
+ getSameLevelItems,
6
+ showContent,
7
+ hideContent,
8
+ getStimulusInstance,
9
+ } from '../utils'
10
+
11
+ const DropdownMenuSubController = class extends Controller<HTMLElement> {
12
+ // targets
13
+ static targets = ['trigger', 'contentContainer', 'content']
14
+ declare readonly triggerTarget: HTMLElement
15
+ declare readonly contentContainerTarget: HTMLElement
16
+ declare readonly contentTarget: HTMLElement
17
+
18
+ // values
19
+ static values = {
20
+ isOpen: Boolean,
21
+ }
22
+ declare isOpenValue: boolean
23
+
24
+ // custom properties
25
+ declare closeTimeout: number
26
+ declare items: HTMLElement[]
27
+ declare DOMKeydownListener: (event: KeyboardEvent) => void
28
+ declare cleanup: () => void
29
+
30
+ connect() {
31
+ this.items = getSameLevelItems({
32
+ content: this.contentTarget,
33
+ items: Array.from(
34
+ this.contentTarget.querySelectorAll(
35
+ '[data-dropdown-menu-target="item"], [data-dropdown-menu-sub-target="trigger"]',
36
+ ),
37
+ ),
38
+ closestContentSelector: '[data-dropdown-menu-sub-target="content"]',
39
+ })
40
+ }
41
+
42
+ open(event: MouseEvent | KeyboardEvent | null = null) {
43
+ clearTimeout(this.closeTimeout)
44
+ this.isOpenValue = true
45
+
46
+ setTimeout(() => {
47
+ if (event instanceof KeyboardEvent) {
48
+ const key = event.key
49
+
50
+ if (['ArrowRight', 'Enter', ' '].includes(key)) {
51
+ this.focusItemByIndex(null, 0)
52
+ }
53
+ }
54
+ }, ON_OPEN_FOCUS_DELAY)
55
+ }
56
+
57
+ close() {
58
+ this.closeTimeout = window.setTimeout(() => {
59
+ this.isOpenValue = false
60
+ }, 250)
61
+ }
62
+
63
+ closeOnLeftKeydown() {
64
+ this.closeImmediately()
65
+ this.triggerTarget.focus()
66
+ }
67
+
68
+ focusItemByIndex(event: KeyboardEvent | null, index: number | null) {
69
+ if (event) {
70
+ const key = event.key
71
+
72
+ if (key === 'ArrowUp') {
73
+ this.items[this.items.length - 1].focus()
74
+ } else {
75
+ this.items[0].focus()
76
+ }
77
+ } else if (index !== null) {
78
+ this.items[index].focus()
79
+ }
80
+ }
81
+
82
+ closeParentSubMenu() {
83
+ const parentContent = this.triggerTarget.closest(
84
+ '[data-dropdown-menu-sub-target="content"]',
85
+ )
86
+
87
+ if (parentContent) {
88
+ const subMenu = parentContent.closest(
89
+ '[data-shadcn-phlexcomponents="dropdown-menu-sub"]',
90
+ ) as HTMLElement
91
+
92
+ if (subMenu) {
93
+ const subMenuController = getStimulusInstance<DropdownMenuSub>(
94
+ 'dropdown-menu-sub',
95
+ subMenu,
96
+ )
97
+
98
+ if (subMenuController) {
99
+ subMenuController.closeImmediately()
100
+ setTimeout(() => {
101
+ subMenuController.triggerTarget.focus()
102
+ }, 100)
103
+ }
104
+ }
105
+ }
106
+ }
107
+
108
+ closeImmediately() {
109
+ this.isOpenValue = false
110
+ }
111
+
112
+ isOpenValueChanged(isOpen: boolean) {
113
+ if (isOpen) {
114
+ showContent({
115
+ trigger: this.triggerTarget,
116
+ content: this.contentTarget,
117
+ contentContainer: this.contentContainerTarget,
118
+ })
119
+
120
+ this.cleanup = initFloatingUi({
121
+ referenceElement: this.triggerTarget,
122
+ floatingElement: this.contentContainerTarget,
123
+ side: this.contentTarget.dataset.side,
124
+ align: this.contentTarget.dataset.align,
125
+ sideOffset: -2,
126
+ })
127
+ } else {
128
+ this.closeTimeout = window.setTimeout(() => {
129
+ hideContent({
130
+ trigger: this.triggerTarget,
131
+ content: this.contentTarget,
132
+ contentContainer: this.contentContainerTarget,
133
+ })
134
+ })
135
+
136
+ this.cleanupEventListeners()
137
+ }
138
+ }
139
+
140
+ disconnect() {
141
+ this.cleanupEventListeners()
142
+ }
143
+
144
+ protected cleanupEventListeners() {
145
+ if (this.cleanup) this.cleanup()
146
+ }
147
+ }
148
+
149
+ type DropdownMenuSub = InstanceType<typeof DropdownMenuSubController>
150
+
151
+ export { DropdownMenuSubController }
152
+ export type { DropdownMenuSub }
@@ -0,0 +1,27 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+
3
+ const FormFieldController = class extends Controller {
4
+ connect() {
5
+ const hintContainer = this.element.querySelector('[data-remove-label]')
6
+ const labelContainer = this.element.querySelector('[data-remove-hint]')
7
+
8
+ if (hintContainer) {
9
+ const label = hintContainer.querySelector('label') as HTMLElement
10
+ const hint = hintContainer.querySelector('p') as HTMLElement
11
+ label.remove()
12
+ hintContainer.replaceWith(hint)
13
+ }
14
+
15
+ if (labelContainer) {
16
+ const hint = labelContainer.querySelector('p') as HTMLElement
17
+ const label = labelContainer.querySelector('label') as HTMLElement
18
+ hint.remove()
19
+ labelContainer.replaceWith(label)
20
+ }
21
+ }
22
+ }
23
+
24
+ type FormField = InstanceType<typeof FormFieldController>
25
+
26
+ export { FormFieldController }
27
+ export type { FormField }
@@ -0,0 +1,103 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+ import { useHover } from 'stimulus-use'
3
+ import { initFloatingUi } from '../utils/floating_ui'
4
+ import { showContent, hideContent } from '../utils'
5
+
6
+ const HoverCardController = class extends Controller<HTMLElement> {
7
+ // targets
8
+ static targets = ['trigger', 'content', 'contentContainer']
9
+ declare readonly triggerTarget: HTMLElement
10
+ declare readonly contentTarget: HTMLElement
11
+ declare readonly contentContainerTarget: HTMLElement
12
+
13
+ // values
14
+ static values = {
15
+ isOpen: Boolean,
16
+ }
17
+ declare isOpenValue: boolean
18
+
19
+ // custom properties
20
+ declare closeTimeout: number
21
+ declare DOMKeydownListener: (event: KeyboardEvent) => void
22
+ declare cleanup: () => void
23
+
24
+ connect() {
25
+ this.DOMKeydownListener = this.onDOMKeydown.bind(this)
26
+ useHover(this, { element: this.triggerTarget, dispatchEvent: false })
27
+ }
28
+
29
+ open() {
30
+ window.clearTimeout(this.closeTimeout)
31
+ this.isOpenValue = true
32
+ }
33
+
34
+ close() {
35
+ this.closeTimeout = window.setTimeout(() => {
36
+ this.isOpenValue = false
37
+ }, 250)
38
+ }
39
+
40
+ // for useHover
41
+ mouseEnter() {
42
+ this.open()
43
+ }
44
+
45
+ // for useHover
46
+ mouseLeave() {
47
+ this.close()
48
+ }
49
+
50
+ isOpenValueChanged(isOpen: boolean) {
51
+ if (isOpen) {
52
+ showContent({
53
+ content: this.contentTarget,
54
+ contentContainer: this.contentContainerTarget,
55
+ })
56
+
57
+ this.setupEventListeners()
58
+
59
+ this.cleanup = initFloatingUi({
60
+ referenceElement: this.triggerTarget,
61
+ floatingElement: this.contentContainerTarget,
62
+ side: this.contentTarget.dataset.side,
63
+ align: this.contentTarget.dataset.align,
64
+ sideOffset: 4,
65
+ })
66
+ } else {
67
+ hideContent({
68
+ content: this.contentTarget,
69
+ contentContainer: this.contentContainerTarget,
70
+ })
71
+
72
+ this.cleanupEventListeners()
73
+ }
74
+ }
75
+
76
+ disconnect() {
77
+ this.cleanupEventListeners()
78
+ }
79
+
80
+ protected setupEventListeners() {
81
+ document.addEventListener('keydown', this.DOMKeydownListener)
82
+ }
83
+
84
+ protected cleanupEventListeners() {
85
+ if (this.cleanup) this.cleanup()
86
+ document.removeEventListener('keydown', this.DOMKeydownListener)
87
+ }
88
+
89
+ protected onDOMKeydown(event: KeyboardEvent) {
90
+ if (!this.isOpenValue) return
91
+
92
+ const key = event.key
93
+
94
+ if (key === 'Escape') {
95
+ this.close()
96
+ }
97
+ }
98
+ }
99
+
100
+ type HoverCard = InstanceType<typeof HoverCardController>
101
+
102
+ export { HoverCardController }
103
+ export type { HoverCard }
@@ -1,15 +1,20 @@
1
1
  import { Controller } from '@hotwired/stimulus'
2
2
 
3
- export default class extends Controller {
3
+ const LoadingButtonController = class extends Controller<HTMLButtonElement> {
4
4
  connect() {
5
5
  const el = this.element
6
6
  const form = el.closest('form')
7
7
 
8
8
  if (form && form.dataset.turbo === 'false') {
9
9
  form.addEventListener('submit', () => {
10
- form.ariaBusy = true
10
+ form.ariaBusy = 'true'
11
11
  el.disabled = true
12
12
  })
13
13
  }
14
14
  }
15
15
  }
16
+
17
+ type LoadingButton = InstanceType<typeof LoadingButtonController>
18
+
19
+ export { LoadingButtonController }
20
+ export type { LoadingButton }
@@ -0,0 +1,118 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+ import { useClickOutside } from 'stimulus-use'
3
+ import { initFloatingUi } from '../utils/floating_ui'
4
+ import {
5
+ focusTrigger,
6
+ getFocusableElements,
7
+ showContent,
8
+ hideContent,
9
+ onClickOutside,
10
+ handleTabNavigation,
11
+ focusElement,
12
+ } from '../utils'
13
+
14
+ const PopoverController = class extends Controller<HTMLElement> {
15
+ // targets
16
+ static targets = ['trigger', 'contentContainer', 'content']
17
+ declare readonly triggerTarget: HTMLElement
18
+ declare readonly contentContainerTarget: HTMLElement
19
+ declare readonly contentTarget: HTMLElement
20
+
21
+ // values
22
+ static values = { isOpen: Boolean }
23
+ declare isOpenValue: boolean
24
+
25
+ // custom properties
26
+ declare DOMKeydownListener: (event: KeyboardEvent) => void
27
+ declare cleanup: () => void
28
+
29
+ connect() {
30
+ this.DOMKeydownListener = this.onDOMKeydown.bind(this)
31
+ useClickOutside(this, { element: this.contentTarget, dispatchEvent: false })
32
+ }
33
+
34
+ toggle() {
35
+ if (this.isOpenValue) {
36
+ this.close()
37
+ } else {
38
+ this.open()
39
+ }
40
+ }
41
+
42
+ open() {
43
+ this.isOpenValue = true
44
+ }
45
+
46
+ close() {
47
+ this.isOpenValue = false
48
+ }
49
+
50
+ clickOutside(event: MouseEvent) {
51
+ onClickOutside(this, event)
52
+ }
53
+
54
+ isOpenValueChanged(isOpen: boolean, previousIsOpen: boolean) {
55
+ if (isOpen) {
56
+ showContent({
57
+ trigger: this.triggerTarget,
58
+ content: this.contentTarget,
59
+ contentContainer: this.contentContainerTarget,
60
+ })
61
+
62
+ this.cleanup = initFloatingUi({
63
+ referenceElement: this.triggerTarget,
64
+ floatingElement: this.contentContainerTarget,
65
+ side: this.contentTarget.dataset.side,
66
+ align: this.contentTarget.dataset.align,
67
+ sideOffset: 4,
68
+ })
69
+
70
+ const focusableElements = getFocusableElements(this.contentTarget)
71
+ focusElement(focusableElements[0])
72
+
73
+ this.setupEventListeners()
74
+ } else {
75
+ hideContent({
76
+ trigger: this.triggerTarget,
77
+ content: this.contentTarget,
78
+ contentContainer: this.contentContainerTarget,
79
+ })
80
+
81
+ if (previousIsOpen) {
82
+ focusTrigger(this.triggerTarget)
83
+ }
84
+
85
+ this.cleanupEventListeners()
86
+ }
87
+ }
88
+
89
+ disconnect() {
90
+ this.cleanupEventListeners()
91
+ }
92
+
93
+ protected setupEventListeners() {
94
+ document.addEventListener('keydown', this.DOMKeydownListener)
95
+ }
96
+
97
+ protected cleanupEventListeners() {
98
+ if (this.cleanup) this.cleanup()
99
+ document.removeEventListener('keydown', this.DOMKeydownListener)
100
+ }
101
+
102
+ protected onDOMKeydown(event: KeyboardEvent) {
103
+ if (!this.isOpenValue) return
104
+
105
+ const key = event.key
106
+
107
+ if (key === 'Escape') {
108
+ this.close()
109
+ } else if (key === 'Tab') {
110
+ handleTabNavigation(this.contentTarget, event)
111
+ }
112
+ }
113
+ }
114
+
115
+ type Popover = InstanceType<typeof PopoverController>
116
+
117
+ export { PopoverController }
118
+ export type { Popover }
@@ -0,0 +1,23 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+
3
+ const ProgressController = class extends Controller {
4
+ // targets
5
+ static targets = ['indicator']
6
+ declare readonly indicatorTarget: HTMLElement
7
+
8
+ // values
9
+ static values = {
10
+ percent: Number,
11
+ }
12
+ declare percentValue: number
13
+
14
+ percentValueChanged(value: number) {
15
+ this.element.setAttribute('aria-valuenow', `${value}`)
16
+ this.indicatorTarget.style.transform = `translateX(-${100 - value}%)`
17
+ }
18
+ }
19
+
20
+ type Progress = InstanceType<typeof ProgressController>
21
+
22
+ export { ProgressController }
23
+ export type { Progress }
@@ -0,0 +1,113 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+
3
+ const RadioGroupController = class extends Controller<HTMLElement> {
4
+ // targets
5
+ static targets = ['item', 'input', 'indicator']
6
+ declare readonly itemTargets: HTMLInputElement[]
7
+ declare readonly inputTargets: HTMLInputElement[]
8
+ declare readonly indicatorTargets: HTMLInputElement[]
9
+
10
+ // values
11
+ static values = {
12
+ selected: String,
13
+ }
14
+ declare selectedValue: string
15
+
16
+ connect() {
17
+ if (!this.selectedValue) {
18
+ this.itemTargets[0].tabIndex = 0
19
+ }
20
+ }
21
+
22
+ select(event: MouseEvent) {
23
+ const item = event.currentTarget as HTMLInputElement
24
+ this.selectedValue = item.dataset.value as string
25
+ }
26
+
27
+ selectItem(event: KeyboardEvent) {
28
+ const focusableItems = this.itemTargets.filter(
29
+ (t) => !t.disabled,
30
+ ) as HTMLInputElement[]
31
+
32
+ const item = event.currentTarget as HTMLInputElement
33
+ const index = focusableItems.indexOf(item)
34
+ const key = event.key
35
+ let newIndex = 0
36
+
37
+ if (['ArrowUp', 'ArrowLeft'].includes(key)) {
38
+ newIndex = index - 1
39
+
40
+ if (newIndex < 0) {
41
+ newIndex = focusableItems.length - 1
42
+ }
43
+ } else {
44
+ newIndex = index + 1
45
+
46
+ if (newIndex > focusableItems.length - 1) {
47
+ newIndex = 0
48
+ }
49
+ }
50
+
51
+ this.selectedValue = focusableItems[newIndex].dataset.value as string
52
+ }
53
+
54
+ preventDefault(event: KeyboardEvent) {
55
+ event.preventDefault()
56
+ }
57
+
58
+ focusItem() {
59
+ const item = this.itemTargets.find(
60
+ (i) => i.dataset.value === this.selectedValue,
61
+ )
62
+
63
+ if (!item) return
64
+
65
+ // Focus first item that is not disabled and allow it to be focused
66
+ if (item.disabled) {
67
+ item.tabIndex = -1
68
+
69
+ const focusableItems = this.itemTargets.filter(
70
+ (t) => !t.disabled,
71
+ ) as HTMLInputElement[]
72
+
73
+ if (focusableItems.length > 0) {
74
+ focusableItems[0].focus()
75
+ focusableItems[0].tabIndex = 0
76
+ }
77
+ } else {
78
+ item.focus()
79
+ }
80
+ }
81
+
82
+ selectedValueChanged(value: string) {
83
+ this.itemTargets.forEach((item) => {
84
+ const input = item.querySelector(
85
+ '[data-radio-group-target="input"]',
86
+ ) as HTMLInputElement
87
+ const indicator = item.querySelector(
88
+ '[data-radio-group-target="indicator"]',
89
+ ) as HTMLInputElement
90
+
91
+ if (value === item.dataset.value) {
92
+ input.checked = true
93
+ item.tabIndex = 0
94
+ item.ariaChecked = 'true'
95
+ item.dataset.state = 'checked'
96
+ indicator.classList.remove('hidden')
97
+ } else {
98
+ input.checked = false
99
+ item.tabIndex = -1
100
+ item.ariaChecked = 'false'
101
+ item.dataset.state = 'unchecked'
102
+ indicator.classList.add('hidden')
103
+ }
104
+ })
105
+
106
+ this.focusItem()
107
+ }
108
+ }
109
+
110
+ type RadioGroup = InstanceType<typeof RadioGroupController>
111
+
112
+ export { RadioGroupController }
113
+ export type { RadioGroup }