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,253 @@
1
+ import { Calendar, Options } from 'vanilla-calendar-pro'
2
+ import { DatePickerController } from './date_picker_controller'
3
+ import dayjs from 'dayjs'
4
+ import customParseFormat from 'dayjs/plugin/customParseFormat'
5
+ import utc from 'dayjs/plugin/utc'
6
+ dayjs.extend(customParseFormat)
7
+ dayjs.extend(utc)
8
+
9
+ const DELIMITER = ' - '
10
+ const DAYJS_FORMAT = 'YYYY-MM-DD'
11
+
12
+ const DateRangePickerController = class extends DatePickerController {
13
+ // targets
14
+ static targets = [
15
+ 'trigger',
16
+ 'triggerText',
17
+ 'contentContainer',
18
+ 'content',
19
+ 'input',
20
+ 'hiddenInput',
21
+ 'endHiddenInput',
22
+ 'inputContainer',
23
+ 'calendar',
24
+ 'overlay',
25
+ ]
26
+ declare readonly endHiddenInputTarget: HTMLInputElement
27
+
28
+ // values
29
+ static values = {
30
+ isOpen: Boolean,
31
+ date: String,
32
+ endDate: String,
33
+ }
34
+ declare endDateValue: string
35
+
36
+ inputBlur() {
37
+ const dates = this.calendar.context.selectedDates
38
+ const startDate = dates[0]
39
+ const endDate = dates[1]
40
+ let datesDisplay = ''
41
+
42
+ if (startDate) {
43
+ datesDisplay = `${dayjs(startDate).format(this.format)}${DELIMITER}`
44
+ }
45
+
46
+ if (endDate) {
47
+ datesDisplay = `${datesDisplay}${dayjs(endDate).format(this.format)}`
48
+ }
49
+
50
+ this.inputTarget.value = datesDisplay
51
+ this.inputContainerTarget.dataset.focus = 'false'
52
+ }
53
+
54
+ inputDate(event: KeyboardEvent) {
55
+ const value = (event.target as HTMLInputElement).value
56
+ const dates = value.split(DELIMITER).filter((d) => d.length > 0)
57
+
58
+ if (dates.length > 0) {
59
+ const startDate = dates[0]
60
+ const endDate = dates[1]
61
+ let selectedDates: string[] = this.calendar.context.selectedDates
62
+
63
+ if (dayjs(startDate, this.format, true).isValid()) {
64
+ const dayjsDate = dayjs(value, this.format).format(DAYJS_FORMAT)
65
+ selectedDates[0] = dayjsDate
66
+ }
67
+
68
+ if (dayjs(endDate, this.format, true).isValid()) {
69
+ const dayjsDate = dayjs(endDate, this.format).format(DAYJS_FORMAT)
70
+ selectedDates[1] = dayjsDate
71
+ }
72
+
73
+ selectedDates = selectedDates.filter((d) => !!d)
74
+
75
+ this.calendar.set({
76
+ selectedDates: selectedDates,
77
+ })
78
+ if (selectedDates[0]) {
79
+ this.dateValue = selectedDates[0]
80
+ }
81
+ if (selectedDates[1]) {
82
+ this.endDateValue = selectedDates[1]
83
+ }
84
+ } else {
85
+ this.calendar.set({
86
+ selectedDates: [],
87
+ })
88
+ this.dateValue = ''
89
+ this.endDateValue = ''
90
+ }
91
+ }
92
+
93
+ dateValueChanged(value: string) {
94
+ this.onClickDateListener = this.onClickDate.bind(this)
95
+
96
+ const endDate = this.endDateValue
97
+ let datesDisplay = ''
98
+
99
+ if (value && value.length > 0) {
100
+ const dayjsDate = dayjs(value)
101
+ const formattedDate = dayjsDate.format(this.format)
102
+ this.hiddenInputTarget.value = dayjsDate.utc().format()
103
+
104
+ if (endDate) {
105
+ datesDisplay = `${formattedDate}${DELIMITER}${dayjs(endDate).format(
106
+ this.format,
107
+ )}`
108
+ } else {
109
+ datesDisplay = `${formattedDate}${DELIMITER}`
110
+ }
111
+ } else {
112
+ this.hiddenInputTarget.value = ''
113
+
114
+ if (endDate) {
115
+ datesDisplay = `${DELIMITER}${dayjs(endDate).format(this.format)}`
116
+ }
117
+ }
118
+
119
+ if (this.hasInputTarget) this.inputTarget.value = datesDisplay
120
+ if (this.hasTriggerTextTarget) {
121
+ const hasValue = (!!value && value.length > 0) || !!endDate
122
+
123
+ this.triggerTarget.dataset.hasValue = `${hasValue}`
124
+
125
+ if (this.triggerTarget.dataset.placeholder && !hasValue) {
126
+ this.triggerTextTarget.textContent =
127
+ this.triggerTarget.dataset.placeholder
128
+ } else {
129
+ this.triggerTextTarget.textContent = datesDisplay
130
+ }
131
+ }
132
+ }
133
+
134
+ endDateValueChanged(value: string) {
135
+ const startDate = this.dateValue
136
+ let datesDisplay = ''
137
+
138
+ if (value && value.length > 0) {
139
+ const dayjsDate = dayjs(value)
140
+ const formattedDate = dayjsDate.format(this.format)
141
+ this.endHiddenInputTarget.value = dayjsDate.utc().format()
142
+
143
+ if (startDate) {
144
+ datesDisplay = `${dayjs(startDate).format(
145
+ this.format,
146
+ )}${DELIMITER}${formattedDate}`
147
+ } else {
148
+ datesDisplay = `${DELIMITER}${formattedDate}`
149
+ }
150
+ } else {
151
+ this.endHiddenInputTarget.value = ''
152
+
153
+ if (startDate) {
154
+ datesDisplay = `${dayjs(startDate).format(this.format)}${DELIMITER}`
155
+ }
156
+ }
157
+
158
+ if (this.hasInputTarget) this.inputTarget.value = datesDisplay
159
+
160
+ if (this.hasTriggerTextTarget) {
161
+ const hasValue = (!!value && value.length > 0) || !!startDate
162
+ this.triggerTarget.dataset.hasValue = `${hasValue}`
163
+
164
+ if (this.triggerTarget.dataset.placeholder && !hasValue) {
165
+ this.triggerTextTarget.textContent =
166
+ this.triggerTarget.dataset.placeholder
167
+ } else {
168
+ this.triggerTextTarget.textContent = datesDisplay
169
+ }
170
+ }
171
+ }
172
+
173
+ protected getOptions() {
174
+ let options = {
175
+ type: 'multiple',
176
+ selectionDatesMode: 'multiple-ranged',
177
+ displayMonthsCount: 2,
178
+ monthsToSwitch: 1,
179
+ displayDatesOutside: false,
180
+ enableJumpToSelectedDate: true,
181
+ onClickDate: this.onClickDateListener,
182
+ } as Options
183
+
184
+ const selectedDates = []
185
+
186
+ const startDate = this.element.dataset.value
187
+ const endDate = this.element.dataset.endValue
188
+
189
+ if (startDate && dayjs(startDate).isValid()) {
190
+ const date = dayjs(startDate).format(DAYJS_FORMAT)
191
+ selectedDates.push(date)
192
+ }
193
+
194
+ if (endDate && dayjs(endDate).isValid()) {
195
+ const date = dayjs(endDate).format(DAYJS_FORMAT)
196
+ selectedDates.push(date)
197
+ }
198
+
199
+ options.selectedDates = selectedDates
200
+
201
+ try {
202
+ options = {
203
+ ...options,
204
+ ...JSON.parse(this.element.dataset.options || ''),
205
+ }
206
+ } catch {
207
+ // noop
208
+ }
209
+
210
+ if (options.selectedDates && options.selectedDates.length > 0) {
211
+ this.dateValue = `${options.selectedDates[0]}`
212
+ if (options.selectedDates[1]) {
213
+ this.endDateValue = `${options.selectedDates[1]}`
214
+ }
215
+ }
216
+
217
+ return options
218
+ }
219
+
220
+ protected onClickDate(self: Calendar) {
221
+ const dates = self.context.selectedDates
222
+
223
+ if (dates.length > 0) {
224
+ const startDate = dates[0]
225
+ const endDate = dates[1]
226
+
227
+ this.dateValue = startDate
228
+
229
+ if (endDate) {
230
+ this.endDateValue = endDate
231
+ this.close()
232
+ } else {
233
+ this.endDateValue = ''
234
+ }
235
+ } else {
236
+ this.dateValue = ''
237
+ this.endDateValue = ''
238
+ }
239
+ }
240
+
241
+ protected setupInputMask() {
242
+ const pattern = this.format.replace(/[^\/]/g, '9')
243
+ const im = new Inputmask(`${pattern}${DELIMITER}${pattern}`, {
244
+ showMaskOnHover: false,
245
+ })
246
+ im.mask(this.inputTarget)
247
+ }
248
+ }
249
+
250
+ type DateRangePicker = InstanceType<typeof DateRangePickerController>
251
+
252
+ export { DateRangePickerController }
253
+ export type { DateRangePicker }
@@ -0,0 +1,115 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+ import {
3
+ focusElement,
4
+ focusTrigger,
5
+ showContent,
6
+ hideContent,
7
+ getFocusableElements,
8
+ anyNestedComponentsOpen,
9
+ handleTabNavigation,
10
+ } from '../utils'
11
+
12
+ const DialogController = class extends Controller<HTMLElement> {
13
+ // targets
14
+ static targets = ['trigger', 'content', 'overlay']
15
+ declare readonly triggerTarget: HTMLElement
16
+ declare readonly contentTarget: HTMLElement
17
+ declare readonly overlayTarget: HTMLElement
18
+
19
+ // values
20
+ static values = {
21
+ isOpen: Boolean,
22
+ }
23
+ declare isOpenValue: boolean
24
+
25
+ // custom properties
26
+ declare trigger: HTMLElement
27
+ declare DOMKeydownListener: (event: KeyboardEvent) => void
28
+ declare DOMClickListener: (event: MouseEvent) => void
29
+
30
+ connect() {
31
+ this.DOMKeydownListener = this.onDOMKeydown.bind(this)
32
+ this.DOMClickListener = this.onDOMClick.bind(this)
33
+ }
34
+
35
+ open() {
36
+ this.isOpenValue = true
37
+ }
38
+
39
+ close() {
40
+ this.isOpenValue = false
41
+ }
42
+
43
+ isOpenValueChanged(isOpen: boolean, previousIsOpen: boolean) {
44
+ if (isOpen) {
45
+ showContent({
46
+ trigger: this.triggerTarget,
47
+ content: this.contentTarget,
48
+ contentContainer: this.contentTarget,
49
+ appendToBody: true,
50
+ overlay: this.overlayTarget,
51
+ })
52
+
53
+ const focusableElements = getFocusableElements(this.contentTarget)
54
+ focusElement(focusableElements[0])
55
+
56
+ this.setupEventListeners()
57
+ } else {
58
+ hideContent({
59
+ trigger: this.triggerTarget,
60
+ content: this.contentTarget,
61
+ contentContainer: this.contentTarget,
62
+ overlay: this.overlayTarget,
63
+ })
64
+
65
+ if (previousIsOpen) {
66
+ focusTrigger(this.triggerTarget)
67
+ }
68
+
69
+ this.cleanupEventListeners()
70
+ }
71
+ }
72
+
73
+ disconnect() {
74
+ this.cleanupEventListeners()
75
+ }
76
+
77
+ protected onDOMClick(event: MouseEvent) {
78
+ if (!this.isOpenValue) return
79
+
80
+ const target = event.target as HTMLElement
81
+ if (target === this.triggerTarget) return
82
+ if (this.contentTarget.contains(target)) return
83
+
84
+ const shouldClose = !anyNestedComponentsOpen(this.contentTarget)
85
+ if (shouldClose) this.close()
86
+ }
87
+
88
+ onDOMKeydown(event: KeyboardEvent) {
89
+ if (!this.isOpenValue) return
90
+
91
+ const key = event.key
92
+
93
+ if (key === 'Escape') {
94
+ const shouldClose = !anyNestedComponentsOpen(this.contentTarget)
95
+ if (shouldClose) this.close()
96
+ } else if (key === 'Tab') {
97
+ handleTabNavigation(this.contentTarget, event)
98
+ }
99
+ }
100
+
101
+ setupEventListeners() {
102
+ document.addEventListener('keydown', this.DOMKeydownListener)
103
+ document.addEventListener('pointerdown', this.DOMClickListener)
104
+ }
105
+
106
+ cleanupEventListeners() {
107
+ document.removeEventListener('keydown', this.DOMKeydownListener)
108
+ document.removeEventListener('pointerdown', this.DOMClickListener)
109
+ }
110
+ }
111
+
112
+ type Dialog = InstanceType<typeof DialogController>
113
+
114
+ export { DialogController }
115
+ export type { Dialog }
@@ -0,0 +1,309 @@
1
+ import { DropdownMenuSub } from './dropdown_menu_sub_controller'
2
+ import { Select } from './select_controller'
3
+ import { Controller } from '@hotwired/stimulus'
4
+ import { useClickOutside } from 'stimulus-use'
5
+ import { initFloatingUi } from '../utils/floating_ui'
6
+ import {
7
+ getSameLevelItems,
8
+ focusTrigger,
9
+ hideContent,
10
+ showContent,
11
+ lockScroll,
12
+ unlockScroll,
13
+ getStimulusInstance,
14
+ onClickOutside,
15
+ getNextEnabledIndex,
16
+ getPreviousEnabledIndex,
17
+ focusElement,
18
+ } from '../utils'
19
+
20
+ const onKeydown = (controller: DropdownMenu | Select, event: KeyboardEvent) => {
21
+ const key = event.key
22
+
23
+ if (['Tab', 'Enter', ' '].includes(key)) event.preventDefault()
24
+ if (key === 'Home') {
25
+ controller.focusItemByIndex(null, 0)
26
+ } else if (key === 'End') {
27
+ controller.focusItemByIndex(null, controller.items.length - 1)
28
+ } else if (key === 'Escape') {
29
+ controller.close()
30
+ }
31
+ }
32
+
33
+ const focusItemByIndex = (
34
+ controller: DropdownMenu | Select,
35
+ event: KeyboardEvent | null = null,
36
+ index: number | null = null,
37
+ ) => {
38
+ if (event !== null) {
39
+ const key = event.key
40
+
41
+ if (key === 'ArrowUp') {
42
+ controller.items[controller.items.length - 1].focus()
43
+ } else {
44
+ controller.items[0].focus()
45
+ }
46
+ } else if (index !== null) {
47
+ controller.items[index].focus()
48
+ }
49
+ }
50
+
51
+ const DropdownMenuController = class extends Controller<HTMLElement> {
52
+ // targets
53
+ static targets = ['trigger', 'contentContainer', 'content', 'item']
54
+ declare readonly triggerTarget: HTMLElement
55
+ declare readonly contentContainerTarget: HTMLElement
56
+ declare readonly contentTarget: HTMLElement
57
+ declare readonly itemTargets: HTMLElement[]
58
+
59
+ // values
60
+ static values = {
61
+ isOpen: Boolean,
62
+ }
63
+ declare isOpenValue: boolean
64
+
65
+ // custom properties
66
+ declare closestContentSelector: string
67
+ declare items: HTMLElement[]
68
+ declare subMenuControllers: DropdownMenuSub[]
69
+ declare DOMKeydownListener: (event: KeyboardEvent) => void
70
+ declare cleanup: () => void
71
+
72
+ connect() {
73
+ this.closestContentSelector =
74
+ '[data-dropdown-menu-target="content"], [data-dropdown-menu-sub-target="content"]'
75
+ this.items = getSameLevelItems({
76
+ content: this.contentTarget,
77
+ items: this.itemTargets,
78
+ closestContentSelector: this.closestContentSelector,
79
+ })
80
+ useClickOutside(this, { element: this.contentTarget, dispatchEvent: false })
81
+ this.DOMKeydownListener = this.onDOMKeydown.bind(this)
82
+ }
83
+
84
+ toggle(event: MouseEvent) {
85
+ if (this.isOpenValue) {
86
+ this.close()
87
+ } else {
88
+ this.open(event)
89
+ }
90
+ }
91
+
92
+ open(event: MouseEvent | KeyboardEvent) {
93
+ this.isOpenValue = true
94
+
95
+ // Sub menus are not connected to the DOM yet when dropdown menu is connected.
96
+ // So we initialize them here instead of in connect().
97
+ if (this.subMenuControllers === undefined) {
98
+ const subMenuControllers = [] as DropdownMenuSub[]
99
+
100
+ const subMenus = Array.from(
101
+ this.contentTarget.querySelectorAll(
102
+ '[data-shadcn-phlexcomponents="dropdown-menu-sub"]',
103
+ ),
104
+ ) as HTMLElement[]
105
+
106
+ subMenus.forEach((subMenu) => {
107
+ const subMenuController = getStimulusInstance<DropdownMenuSub>(
108
+ 'dropdown-menu-sub',
109
+ subMenu,
110
+ )
111
+
112
+ if (subMenuController) {
113
+ subMenuControllers.push(subMenuController)
114
+ }
115
+ })
116
+
117
+ this.subMenuControllers = subMenuControllers
118
+ }
119
+
120
+ let elementToFocus = null as HTMLElement | null
121
+
122
+ if (event instanceof KeyboardEvent) {
123
+ const key = event.key
124
+
125
+ if (['ArrowDown', 'Enter', ' '].includes(key)) {
126
+ elementToFocus = this.items[0]
127
+ }
128
+ } else {
129
+ elementToFocus = this.contentTarget
130
+ }
131
+
132
+ focusElement(elementToFocus)
133
+ }
134
+
135
+ close() {
136
+ this.isOpenValue = false
137
+ this.subMenuControllers.forEach((subMenuController) => {
138
+ subMenuController.closeImmediately()
139
+ })
140
+ }
141
+
142
+ focusItem(event: MouseEvent | KeyboardEvent) {
143
+ const item = event.currentTarget as HTMLElement
144
+ let items = [] as HTMLElement[]
145
+ const content = item.closest(this.closestContentSelector) as HTMLElement
146
+
147
+ const isSubMenu =
148
+ content.dataset.shadcnPhlexcomponents === 'dropdown-menu-sub-content'
149
+
150
+ if (isSubMenu) {
151
+ const subMenu = content.closest(
152
+ '[data-shadcn-phlexcomponents="dropdown-menu-sub"]',
153
+ )
154
+ const subMenuController = this.subMenuControllers.find(
155
+ (subMenuController) => subMenuController.element == subMenu,
156
+ )
157
+ if (subMenuController) {
158
+ items = subMenuController.items
159
+ }
160
+ } else {
161
+ items = this.items
162
+ }
163
+
164
+ const index = items.indexOf(item)
165
+
166
+ if (event instanceof KeyboardEvent) {
167
+ const key = event.key
168
+ let newIndex = 0
169
+
170
+ if (key === 'ArrowUp') {
171
+ newIndex = getPreviousEnabledIndex({
172
+ items,
173
+ currentIndex: index,
174
+ wrapAround: false,
175
+ })
176
+ } else {
177
+ newIndex = getNextEnabledIndex({
178
+ items,
179
+ currentIndex: index,
180
+ wrapAround: false,
181
+ })
182
+ }
183
+
184
+ items[newIndex].focus()
185
+ } else {
186
+ // item mouseover event
187
+ items[index].focus()
188
+ }
189
+
190
+ // Close submenus on the same level
191
+ const subMenusInContent = Array.from(
192
+ content.querySelectorAll(
193
+ '[data-shadcn-phlexcomponents="dropdown-menu-sub"]',
194
+ ),
195
+ ) as HTMLElement[]
196
+
197
+ subMenusInContent.forEach((subMenu) => {
198
+ const subMenuController = this.subMenuControllers.find(
199
+ (subMenuController) => subMenuController.element == subMenu,
200
+ )
201
+
202
+ if (subMenuController) {
203
+ subMenuController.closeImmediately()
204
+ }
205
+ })
206
+ }
207
+
208
+ onItemFocus(event: FocusEvent) {
209
+ const item = event.currentTarget as HTMLElement
210
+ item.tabIndex = 0
211
+ }
212
+
213
+ onItemBlur(event: FocusEvent) {
214
+ const item = event.currentTarget as HTMLElement
215
+ item.tabIndex = -1
216
+ }
217
+
218
+ focusItemByIndex(
219
+ event: KeyboardEvent | null = null,
220
+ index: number | null = null,
221
+ ) {
222
+ focusItemByIndex(this, event, index)
223
+ }
224
+
225
+ focusContent(event: MouseEvent) {
226
+ const item = event.currentTarget as HTMLElement
227
+ const content = item.closest(this.closestContentSelector) as HTMLElement
228
+ content.focus()
229
+ }
230
+
231
+ select(event: MouseEvent | KeyboardEvent) {
232
+ if (event instanceof KeyboardEvent) {
233
+ const key = event.key
234
+ const item = (event.currentTarget || event.target) as HTMLElement
235
+
236
+ // For rails button_to
237
+ if (item && (key === 'Enter' || key === ' ')) {
238
+ item.click()
239
+ }
240
+ }
241
+
242
+ this.close()
243
+ }
244
+
245
+ clickOutside(event: MouseEvent) {
246
+ onClickOutside(this, event)
247
+ }
248
+
249
+ isOpenValueChanged(isOpen: boolean, previousIsOpen: boolean) {
250
+ if (isOpen) {
251
+ lockScroll(this.contentTarget.id)
252
+
253
+ showContent({
254
+ trigger: this.triggerTarget,
255
+ content: this.contentTarget,
256
+ contentContainer: this.contentContainerTarget,
257
+ setEqualWidth: false,
258
+ })
259
+
260
+ this.cleanup = initFloatingUi({
261
+ referenceElement: this.triggerTarget,
262
+ floatingElement: this.contentContainerTarget,
263
+ side: this.contentTarget.dataset.side,
264
+ align: this.contentTarget.dataset.align,
265
+ sideOffset: 4,
266
+ })
267
+
268
+ this.setupEventListeners()
269
+ } else {
270
+ unlockScroll(this.contentTarget.id)
271
+
272
+ hideContent({
273
+ trigger: this.triggerTarget,
274
+ content: this.contentTarget,
275
+ contentContainer: this.contentContainerTarget,
276
+ })
277
+
278
+ if (previousIsOpen) {
279
+ focusTrigger(this.triggerTarget)
280
+ }
281
+
282
+ this.cleanupEventListeners()
283
+ }
284
+ }
285
+
286
+ disconnect() {
287
+ this.cleanupEventListeners()
288
+ }
289
+
290
+ protected onDOMKeydown(event: KeyboardEvent) {
291
+ if (!this.isOpenValue) return
292
+
293
+ onKeydown(this, event)
294
+ }
295
+
296
+ protected setupEventListeners() {
297
+ document.addEventListener('keydown', this.DOMKeydownListener)
298
+ }
299
+
300
+ protected cleanupEventListeners() {
301
+ if (this.cleanup) this.cleanup()
302
+ document.removeEventListener('keydown', this.DOMKeydownListener)
303
+ }
304
+ }
305
+
306
+ type DropdownMenu = InstanceType<typeof DropdownMenuController>
307
+
308
+ export { DropdownMenuController, onKeydown, focusItemByIndex }
309
+ export type { DropdownMenu }