shadcn_phlexcomponents 0.1.5 → 0.1.9

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 (181) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +14 -0
  3. data/app/javascript/controllers/accordion_controller.js +7 -16
  4. data/app/javascript/controllers/alert_dialog_controller.js +5 -141
  5. data/app/javascript/controllers/combobox_controller.js +20 -0
  6. data/app/javascript/controllers/date_picker_controller.js +199 -64
  7. data/app/javascript/controllers/date_range_picker_controller.js +289 -176
  8. data/app/javascript/controllers/dialog_controller.js +19 -64
  9. data/app/javascript/controllers/dropdown_menu_controller.js +15 -37
  10. data/app/javascript/controllers/form_field_controller.js +24 -0
  11. data/app/javascript/controllers/hover_card_controller.js +1 -22
  12. data/app/javascript/controllers/popover_controller.js +20 -31
  13. data/app/javascript/controllers/select_controller.js +32 -52
  14. data/app/javascript/controllers/sidebar_trigger_controller.js +1 -1
  15. data/app/javascript/controllers/toast_controller.js +2 -2
  16. data/app/javascript/controllers/tooltip_controller.js +1 -2
  17. data/app/javascript/shadcn_phlexcomponents.js +53 -0
  18. data/app/javascript/utils.js +184 -0
  19. data/app/stylesheets/date_picker.css +212 -0
  20. data/lib/install/install_shadcn_phlexcomponents.rb +7 -7
  21. data/lib/{components → shadcn_phlexcomponents/components/accordion}/accordion.rb +1 -1
  22. data/lib/{components → shadcn_phlexcomponents/components/accordion}/accordion_content.rb +1 -1
  23. data/lib/{components → shadcn_phlexcomponents/components/accordion}/accordion_item.rb +1 -1
  24. data/lib/{components → shadcn_phlexcomponents/components/accordion}/accordion_trigger.rb +5 -4
  25. data/lib/{components → shadcn_phlexcomponents/components/alert_dialog}/alert_dialog.rb +1 -1
  26. data/lib/{components → shadcn_phlexcomponents/components/alert_dialog}/alert_dialog_action.rb +1 -1
  27. data/lib/{components → shadcn_phlexcomponents/components/alert_dialog}/alert_dialog_action_to.rb +1 -1
  28. data/lib/{components → shadcn_phlexcomponents/components/alert_dialog}/alert_dialog_cancel.rb +1 -1
  29. data/lib/{components → shadcn_phlexcomponents/components/alert_dialog}/alert_dialog_content.rb +2 -2
  30. data/lib/{components → shadcn_phlexcomponents/components/alert_dialog}/alert_dialog_trigger.rb +2 -2
  31. data/lib/{components → shadcn_phlexcomponents/components/avatar}/avatar.rb +1 -1
  32. data/lib/{components → shadcn_phlexcomponents/components/avatar}/avatar_fallback.rb +1 -1
  33. data/lib/{components → shadcn_phlexcomponents/components/avatar}/avatar_image.rb +1 -1
  34. data/lib/{components → shadcn_phlexcomponents/components/badge}/badge.rb +1 -1
  35. data/lib/{components → shadcn_phlexcomponents/components}/base.rb +10 -0
  36. data/lib/{components → shadcn_phlexcomponents/components/breadcrumb}/breadcrumb.rb +2 -0
  37. data/lib/{components → shadcn_phlexcomponents/components/button}/button.rb +5 -5
  38. data/lib/{components → shadcn_phlexcomponents/components/checkbox}/checkbox.rb +5 -5
  39. data/lib/{components → shadcn_phlexcomponents/components/checkbox_group}/checkbox_group.rb +27 -15
  40. data/lib/{components → shadcn_phlexcomponents/components/collapsible}/collapsible.rb +1 -1
  41. data/lib/{components → shadcn_phlexcomponents/components/collapsible}/collapsible_content.rb +1 -1
  42. data/lib/{components → shadcn_phlexcomponents/components/collapsible}/collapsible_trigger.rb +2 -2
  43. data/lib/shadcn_phlexcomponents/components/date_picker/date_picker.rb +87 -0
  44. data/lib/shadcn_phlexcomponents/components/date_picker/date_picker_content.rb +45 -0
  45. data/lib/shadcn_phlexcomponents/components/date_picker/date_picker_trigger.rb +64 -0
  46. data/lib/shadcn_phlexcomponents/components/date_range_picker/date_range_picker.rb +105 -0
  47. data/lib/shadcn_phlexcomponents/components/date_range_picker/date_range_picker_content.rb +9 -0
  48. data/lib/shadcn_phlexcomponents/components/date_range_picker/date_range_picker_trigger.rb +9 -0
  49. data/lib/{components → shadcn_phlexcomponents/components/dialog}/dialog.rb +8 -8
  50. data/lib/{components → shadcn_phlexcomponents/components/dialog}/dialog_close.rb +1 -1
  51. data/lib/{components → shadcn_phlexcomponents/components/dialog}/dialog_content.rb +3 -3
  52. data/lib/{components → shadcn_phlexcomponents/components/dialog}/dialog_trigger.rb +2 -2
  53. data/lib/{components → shadcn_phlexcomponents/components/dropdown_menu}/dropdown_menu.rb +1 -1
  54. data/lib/{components → shadcn_phlexcomponents/components/dropdown_menu}/dropdown_menu_content.rb +9 -9
  55. data/lib/{components → shadcn_phlexcomponents/components/dropdown_menu}/dropdown_menu_item.rb +8 -8
  56. data/lib/{components → shadcn_phlexcomponents/components/dropdown_menu}/dropdown_menu_trigger.rb +5 -5
  57. data/lib/shadcn_phlexcomponents/components/form/form.rb +139 -0
  58. data/lib/shadcn_phlexcomponents/components/form/form_checkbox.rb +83 -0
  59. data/lib/shadcn_phlexcomponents/components/form/form_checkbox_group.rb +116 -0
  60. data/lib/shadcn_phlexcomponents/components/form/form_date_picker.rb +47 -0
  61. data/lib/shadcn_phlexcomponents/components/form/form_date_range_picker.rb +96 -0
  62. data/lib/{components → shadcn_phlexcomponents/components/form}/form_error.rb +6 -2
  63. data/lib/shadcn_phlexcomponents/components/form/form_helpers.rb +108 -0
  64. data/lib/{components → shadcn_phlexcomponents/components/form}/form_hint.rb +6 -2
  65. data/lib/shadcn_phlexcomponents/components/form/form_radio_group.rb +107 -0
  66. data/lib/shadcn_phlexcomponents/components/form/form_select.rb +65 -0
  67. data/lib/shadcn_phlexcomponents/components/form/form_switch.rb +66 -0
  68. data/lib/shadcn_phlexcomponents/components/form/form_textarea.rb +60 -0
  69. data/lib/{components → shadcn_phlexcomponents/components/hover_card}/hover_card.rb +1 -1
  70. data/lib/{components → shadcn_phlexcomponents/components/hover_card}/hover_card_content.rb +1 -1
  71. data/lib/{components → shadcn_phlexcomponents/components/hover_card}/hover_card_trigger.rb +1 -1
  72. data/lib/{components → shadcn_phlexcomponents/components/input}/input.rb +1 -1
  73. data/lib/{components → shadcn_phlexcomponents/components/loading_button}/loading_button.rb +1 -1
  74. data/lib/{components → shadcn_phlexcomponents/components/popover}/popover.rb +1 -1
  75. data/lib/{components → shadcn_phlexcomponents/components/popover}/popover_content.rb +6 -6
  76. data/lib/{components → shadcn_phlexcomponents/components/popover}/popover_trigger.rb +2 -3
  77. data/lib/{components → shadcn_phlexcomponents/components/progress}/progress.rb +3 -3
  78. data/lib/{components → shadcn_phlexcomponents/components/radio_group}/radio_group.rb +33 -7
  79. data/lib/{components → shadcn_phlexcomponents/components/radio_group}/radio_group_item.rb +7 -7
  80. data/lib/{components → shadcn_phlexcomponents/components/select}/select.rb +22 -12
  81. data/lib/{components → shadcn_phlexcomponents/components/select}/select_content.rb +6 -6
  82. data/lib/{components → shadcn_phlexcomponents/components/select}/select_group.rb +1 -1
  83. data/lib/{components → shadcn_phlexcomponents/components/select}/select_item.rb +8 -8
  84. data/lib/{components → shadcn_phlexcomponents/components/select}/select_label.rb +1 -1
  85. data/lib/{components → shadcn_phlexcomponents/components/select}/select_trigger.rb +10 -10
  86. data/lib/{components → shadcn_phlexcomponents/components/sheet}/sheet.rb +1 -1
  87. data/lib/{components → shadcn_phlexcomponents/components/sheet}/sheet_close.rb +1 -1
  88. data/lib/{components → shadcn_phlexcomponents/components/sheet}/sheet_content.rb +3 -3
  89. data/lib/{components → shadcn_phlexcomponents/components/sheet}/sheet_trigger.rb +2 -2
  90. data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar.rb +3 -3
  91. data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_trigger.rb +2 -2
  92. data/lib/{components → shadcn_phlexcomponents/components/switch}/switch.rb +4 -4
  93. data/lib/{components → shadcn_phlexcomponents/components/tabs}/tabs.rb +2 -2
  94. data/lib/{components → shadcn_phlexcomponents/components/tabs}/tabs_content.rb +1 -1
  95. data/lib/{components → shadcn_phlexcomponents/components/tabs}/tabs_trigger.rb +4 -4
  96. data/lib/{components → shadcn_phlexcomponents/components/textarea}/textarea.rb +3 -2
  97. data/lib/{components → shadcn_phlexcomponents/components/theme_switcher}/theme_switcher.rb +2 -2
  98. data/lib/{components → shadcn_phlexcomponents/components/toast}/toast.rb +7 -7
  99. data/lib/{components → shadcn_phlexcomponents/components/toast}/toast_container.rb +1 -1
  100. data/lib/{components → shadcn_phlexcomponents/components/tooltip}/tooltip.rb +3 -3
  101. data/lib/{components → shadcn_phlexcomponents/components/tooltip}/tooltip_content.rb +1 -1
  102. data/lib/{components → shadcn_phlexcomponents/components/tooltip}/tooltip_trigger.rb +1 -1
  103. data/lib/shadcn_phlexcomponents/version.rb +1 -1
  104. metadata +157 -144
  105. data/app/assets/tailwind/vanilla-calendar-pro.css +0 -466
  106. data/app/javascript/controllers/sheet_controller.js +0 -159
  107. data/lib/components/combobox.rb +0 -57
  108. data/lib/components/combobox_item.rb +0 -9
  109. data/lib/components/date_picker.rb +0 -94
  110. data/lib/components/date_range_picker.rb +0 -113
  111. data/lib/components/form.rb +0 -59
  112. /data/app/{assets/tailwind → stylesheets}/choices.css +0 -0
  113. /data/app/{assets/tailwind → stylesheets}/tailwindcss-animate.css +0 -0
  114. /data/lib/{components → shadcn_phlexcomponents/components/alert}/alert.rb +0 -0
  115. /data/lib/{components → shadcn_phlexcomponents/components/alert}/alert_description.rb +0 -0
  116. /data/lib/{components → shadcn_phlexcomponents/components/alert}/alert_title.rb +0 -0
  117. /data/lib/{components → shadcn_phlexcomponents/components/alert_dialog}/alert_dialog_description.rb +0 -0
  118. /data/lib/{components → shadcn_phlexcomponents/components/alert_dialog}/alert_dialog_footer.rb +0 -0
  119. /data/lib/{components → shadcn_phlexcomponents/components/alert_dialog}/alert_dialog_header.rb +0 -0
  120. /data/lib/{components → shadcn_phlexcomponents/components/alert_dialog}/alert_dialog_title.rb +0 -0
  121. /data/lib/{components → shadcn_phlexcomponents/components/aspect_ratio}/aspect_ratio.rb +0 -0
  122. /data/lib/{components → shadcn_phlexcomponents/components/breadcrumb}/breadcrumb_ellipsis.rb +0 -0
  123. /data/lib/{components → shadcn_phlexcomponents/components/breadcrumb}/breadcrumb_item.rb +0 -0
  124. /data/lib/{components → shadcn_phlexcomponents/components/breadcrumb}/breadcrumb_link.rb +0 -0
  125. /data/lib/{components → shadcn_phlexcomponents/components/breadcrumb}/breadcrumb_page.rb +0 -0
  126. /data/lib/{components → shadcn_phlexcomponents/components/breadcrumb}/breadcrumb_separator.rb +0 -0
  127. /data/lib/{components → shadcn_phlexcomponents/components/card}/card.rb +0 -0
  128. /data/lib/{components → shadcn_phlexcomponents/components/card}/card_content.rb +0 -0
  129. /data/lib/{components → shadcn_phlexcomponents/components/card}/card_description.rb +0 -0
  130. /data/lib/{components → shadcn_phlexcomponents/components/card}/card_footer.rb +0 -0
  131. /data/lib/{components → shadcn_phlexcomponents/components/card}/card_header.rb +0 -0
  132. /data/lib/{components → shadcn_phlexcomponents/components/card}/card_title.rb +0 -0
  133. /data/lib/{components → shadcn_phlexcomponents/components/dialog}/dialog_description.rb +0 -0
  134. /data/lib/{components → shadcn_phlexcomponents/components/dialog}/dialog_footer.rb +0 -0
  135. /data/lib/{components → shadcn_phlexcomponents/components/dialog}/dialog_header.rb +0 -0
  136. /data/lib/{components → shadcn_phlexcomponents/components/dialog}/dialog_title.rb +0 -0
  137. /data/lib/{components → shadcn_phlexcomponents/components/dropdown_menu}/dropdown_menu_item_to.rb +0 -0
  138. /data/lib/{components → shadcn_phlexcomponents/components/dropdown_menu}/dropdown_menu_label.rb +0 -0
  139. /data/lib/{components → shadcn_phlexcomponents/components/dropdown_menu}/dropdown_menu_separator.rb +0 -0
  140. /data/lib/{components → shadcn_phlexcomponents/components/form}/form_input.rb +0 -0
  141. /data/lib/{components → shadcn_phlexcomponents/components/label}/label.rb +0 -0
  142. /data/lib/{components → shadcn_phlexcomponents/components/link}/link.rb +0 -0
  143. /data/lib/{components → shadcn_phlexcomponents/components/pagination}/pagination.rb +0 -0
  144. /data/lib/{components → shadcn_phlexcomponents/components/pagination}/pagination_ellipsis.rb +0 -0
  145. /data/lib/{components → shadcn_phlexcomponents/components/pagination}/pagination_link.rb +0 -0
  146. /data/lib/{components → shadcn_phlexcomponents/components/pagination}/pagination_next.rb +0 -0
  147. /data/lib/{components → shadcn_phlexcomponents/components/pagination}/pagination_previous.rb +0 -0
  148. /data/lib/{components → shadcn_phlexcomponents/components/separator}/separator.rb +0 -0
  149. /data/lib/{components → shadcn_phlexcomponents/components/sheet}/sheet_description.rb +0 -0
  150. /data/lib/{components → shadcn_phlexcomponents/components/sheet}/sheet_footer.rb +0 -0
  151. /data/lib/{components → shadcn_phlexcomponents/components/sheet}/sheet_header.rb +0 -0
  152. /data/lib/{components → shadcn_phlexcomponents/components/sheet}/sheet_title.rb +0 -0
  153. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_container.rb +0 -0
  154. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_content.rb +0 -0
  155. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_footer.rb +0 -0
  156. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_group.rb +0 -0
  157. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_group_content.rb +0 -0
  158. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_group_label.rb +0 -0
  159. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_header.rb +0 -0
  160. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_inset.rb +0 -0
  161. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_menu.rb +0 -0
  162. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_menu_button.rb +0 -0
  163. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_menu_item.rb +0 -0
  164. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_menu_sub.rb +0 -0
  165. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_menu_sub_button.rb +0 -0
  166. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_menu_sub_item.rb +0 -0
  167. /data/lib/{components → shadcn_phlexcomponents/components/skeleton}/skeleton.rb +0 -0
  168. /data/lib/{components → shadcn_phlexcomponents/components/table}/table.rb +0 -0
  169. /data/lib/{components → shadcn_phlexcomponents/components/table}/table_body.rb +0 -0
  170. /data/lib/{components → shadcn_phlexcomponents/components/table}/table_caption.rb +0 -0
  171. /data/lib/{components → shadcn_phlexcomponents/components/table}/table_cell.rb +0 -0
  172. /data/lib/{components → shadcn_phlexcomponents/components/table}/table_footer.rb +0 -0
  173. /data/lib/{components → shadcn_phlexcomponents/components/table}/table_head.rb +0 -0
  174. /data/lib/{components → shadcn_phlexcomponents/components/table}/table_header.rb +0 -0
  175. /data/lib/{components → shadcn_phlexcomponents/components/table}/table_row.rb +0 -0
  176. /data/lib/{components → shadcn_phlexcomponents/components/tabs}/tabs_list.rb +0 -0
  177. /data/lib/{components → shadcn_phlexcomponents/components/toast}/toast_action.rb +0 -0
  178. /data/lib/{components → shadcn_phlexcomponents/components/toast}/toast_action_to.rb +0 -0
  179. /data/lib/{components → shadcn_phlexcomponents/components/toast}/toast_content.rb +0 -0
  180. /data/lib/{components → shadcn_phlexcomponents/components/toast}/toast_description.rb +0 -0
  181. /data/lib/{components → shadcn_phlexcomponents/components/toast}/toast_title.rb +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 210b2eb6c1822030026320c38e93ccd0b917c07a76abe13f5bbf2f7b77033898
4
- data.tar.gz: 9122e7c0acfde18b7c52177b435b40e88efd872a1b8e6bfa2c4702a794e0e5bc
3
+ metadata.gz: f01a8b6d7fd3e2f4727726449999ee8e1df8f4385399a045de46390713886e7a
4
+ data.tar.gz: 1fc407c7488a6bba53a23e77a1e912e294dec1c0407fba97abf5ea2d2cf02820
5
5
  SHA512:
6
- metadata.gz: cd7a07542caf9b43afe55355fcdd09855b60bc5f54ac0f8fc3c5a83e35ef654f458c8006baa91afddb1667b9d526916d3758e9f50e6d3e7fd50a8607dfd32979
7
- data.tar.gz: 37510ade39630444cf92d938b197462c78d21a7a41ceae9db67300e24806b70c2ba4391a7eeb3b9ab86ee5ef38427dd98693e1518252f764ef5a3b718834fda6
6
+ metadata.gz: 532c2cddc7f12c798babf37d1e1248ac0034a44b2c359e7fb60e2e481a6be4f83655cff30adc93633f00b3b2bda4df853b1189e097ee65de5335f1016331ad09
7
+ data.tar.gz: 74d475a2b3e633f38db546d8ee820ae788a9abf2becd4699ac1c6b3ff5f5557635a3838791d9cba75764b5184a08794c1107d01a913eb996d2aa3dc238a53b21
data/README.md CHANGED
@@ -37,3 +37,17 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERN
37
37
  ## Code of Conduct
38
38
 
39
39
  Everyone interacting in the ShadcnPhlexcomponents project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/shadcn_phlexcomponents/blob/main/CODE_OF_CONDUCT.md).
40
+
41
+ ## [Unreleased] - YYYY-MM-DD
42
+
43
+ ### Added
44
+
45
+ ### Changed
46
+
47
+ ### Deprecated
48
+
49
+ ### Removed
50
+
51
+ ### Fixed
52
+
53
+ ### Security
@@ -1,4 +1,5 @@
1
1
  import { Controller } from '@hotwired/stimulus'
2
+ import { ANIMATION_OUT_DELAY } from '../utils'
2
3
 
3
4
  export default class extends Controller {
4
5
  static targets = ['trigger', 'content', 'item']
@@ -55,9 +56,7 @@ export default class extends Controller {
55
56
  toggleItem(event) {
56
57
  const trigger = event.currentTarget || event.target
57
58
 
58
- const item = trigger.closest(
59
- '[data-shadcn-phlexcomponents--accordion-target="item"]',
60
- )
59
+ const item = trigger.closest('[data-accordion-target="item"]')
61
60
 
62
61
  if (item.dataset.state === 'open') {
63
62
  this.closeItem(item)
@@ -75,12 +74,8 @@ export default class extends Controller {
75
74
  }
76
75
 
77
76
  openItem(item) {
78
- const button = item.querySelector(
79
- '[data-shadcn-phlexcomponents--accordion-target="trigger"]',
80
- )
81
- const content = item.querySelector(
82
- '[data-shadcn-phlexcomponents--accordion-target="content"]',
83
- )
77
+ const button = item.querySelector('[data-accordion-target="trigger"]')
78
+ const content = item.querySelector('[data-accordion-target="content"]')
84
79
 
85
80
  item.dataset.state = 'open'
86
81
  button.ariaExpanded = true
@@ -90,12 +85,8 @@ export default class extends Controller {
90
85
  }
91
86
 
92
87
  closeItem(item) {
93
- const button = item.querySelector(
94
- '[data-shadcn-phlexcomponents--accordion-target="trigger"]',
95
- )
96
- const content = item.querySelector(
97
- '[data-shadcn-phlexcomponents--accordion-target="content"]',
98
- )
88
+ const button = item.querySelector('[data-accordion-target="trigger"]')
89
+ const content = item.querySelector('[data-accordion-target="content"]')
99
90
 
100
91
  item.dataset.state = 'closed'
101
92
  button.ariaExpanded = false
@@ -104,7 +95,7 @@ export default class extends Controller {
104
95
 
105
96
  setTimeout(() => {
106
97
  content.classList.add('hidden')
107
- }, 150)
98
+ }, ANIMATION_OUT_DELAY)
108
99
  }
109
100
 
110
101
  focusNext(event) {
@@ -1,157 +1,21 @@
1
- import { Controller } from '@hotwired/stimulus'
1
+ import DialogController from './dialog_controller'
2
2
 
3
- export default class extends Controller {
4
- static targets = ['trigger', 'content']
5
-
6
- connect() {
7
- this.DOMClickListener = this.onDOMClick.bind(this)
8
- this.DOMKeydownListener = this.onDOMKeydown.bind(this)
9
-
10
- this.focusableElements = this.contentTarget.querySelectorAll(
11
- 'button, [href], input:not([type="hidden"]), select, textarea, [tabindex]:not([tabindex="-1"])',
12
- )
13
-
14
- this.firstElement = this.focusableElements[0]
15
- this.lastElement = this.focusableElements[this.focusableElements.length - 1]
16
- this.contentElement = document.querySelector(`#${this.contentTarget.id}`)
17
- }
18
-
19
- open() {
20
- this.showOverlay()
21
- this.contentElement.classList.remove('hidden')
22
- this.contentElement.dataset.state = 'open'
23
- this.triggerTarget.ariaExpanded = true
24
- this.setupEventListeners()
25
- this.addInert()
26
-
27
- if (window.innerHeight < document.documentElement.scrollHeight) {
28
- document.body.dataset.scrollLocked = 1
29
- }
30
- document.body.appendChild(this.contentElement)
31
- this.firstElement.focus() // must be after appendChild
32
- }
33
-
34
- close() {
35
- this.contentElement.dataset.state = 'closed'
36
- this.triggerTarget.ariaExpanded = false
37
- this.cleanupEventListeners()
38
- this.removeInert()
39
- this.element.appendChild(this.contentElement)
40
-
41
- setTimeout(() => {
42
- this.contentElement.classList.add('hidden')
43
- }, 100)
44
-
45
- setTimeout(() => {
46
- delete document.body.dataset.scrollLocked
47
- this.removeOverlay()
48
- }, 150)
49
-
50
- this.focusTrigger()
51
- }
52
-
53
- focusTrigger() {
54
- if (this.triggerTarget.dataset.asChild === 'false') {
55
- this.triggerTarget.firstElementChild.focus()
56
- } else {
57
- this.triggerTarget.focus()
58
- }
59
- }
60
-
61
- isOpen() {
62
- return this.triggerTarget.ariaExpanded === 'true'
63
- }
64
-
65
- showOverlay() {
66
- const elem = document.createElement('div')
67
- elem.classList.add(
68
- 'fixed',
69
- 'inset-0',
70
- 'z-50',
71
- 'bg-black/80',
72
- 'data-[state=open]:animate-in',
73
- 'data-[state=closed]:animate-out',
74
- 'data-[state=closed]:fade-out-0',
75
- 'data-[state=open]:fade-in-0',
76
- 'pointer-events-auto',
77
- )
78
- elem.dataset.state = 'open'
79
- elem.ariaHidden = true
80
- elem.dataset.overlay = true
81
- document.body.appendChild(elem)
82
- }
83
-
84
- removeOverlay() {
85
- if (document.querySelector('[data-overlay]')) {
86
- document.querySelector('[data-overlay]').remove()
87
- }
88
- }
89
-
90
- // Global listeners
3
+ export default class extends DialogController {
91
4
  onDOMClick(event) {
92
5
  if (!this.isOpen()) return
93
6
 
94
7
  const target = event.target
95
- const trigger = event.target.closest(
96
- '[data-shadcn-phlexcomponents--alert-dialog-target="trigger"]',
97
- )
8
+ const trigger = event.target.closest('[data-alert-dialog-target="trigger"]')
98
9
 
99
10
  if (trigger) return
100
11
 
101
- const close = target.closest(
102
- '[data-action*="shadcn-phlexcomponents--alert-dialog#close"]',
103
- )
12
+ const close = target.closest('[data-action*="alert-dialog#close"]')
104
13
 
105
14
  if (
106
15
  close ||
107
16
  (target.dataset.action &&
108
- target.dataset.action.includes(
109
- 'shadcn-phlexcomponents--alert-dialog#close',
110
- ))
17
+ target.dataset.action.includes('alert-dialog#close'))
111
18
  )
112
19
  this.close()
113
20
  }
114
-
115
- onDOMKeydown(event) {
116
- if (!this.isOpen()) return
117
-
118
- const key = event.key
119
-
120
- if (key === 'Escape') {
121
- this.close()
122
- } else if (key === 'Tab') {
123
- // If Shift + Tab pressed on first element, go to last element
124
- if (event.shiftKey && document.activeElement === this.firstElement) {
125
- event.preventDefault()
126
- this.lastElement.focus()
127
- }
128
- // If Tab pressed on last element, go to first element
129
- else if (!event.shiftKey && document.activeElement === this.lastElement) {
130
- event.preventDefault()
131
- this.firstElement.focus()
132
- }
133
- }
134
- }
135
-
136
- setupEventListeners() {
137
- document.addEventListener('click', this.DOMClickListener)
138
- document.addEventListener('keydown', this.DOMKeydownListener)
139
- }
140
-
141
- cleanupEventListeners() {
142
- document.removeEventListener('click', this.DOMClickListener)
143
- document.removeEventListener('keydown', this.DOMKeydownListener)
144
- }
145
-
146
- addInert() {
147
- Array.from(document.body.children)
148
- .filter((el) => el !== this.contentElement)
149
- .forEach((el) => el.setAttribute('inert', ''))
150
- }
151
-
152
- removeInert() {
153
- Array.from(document.body.children)
154
- .filter((el) => el.hasAttribute('inert'))
155
- .forEach((el) => el.removeAttribute('inert'))
156
- }
157
21
  }
@@ -1,9 +1,12 @@
1
1
  import { Controller } from '@hotwired/stimulus'
2
2
  import Choices from 'choices.js'
3
+
3
4
  export default class extends Controller {
4
5
  static targets = ['select']
5
6
 
6
7
  connect() {
8
+ this.DOMKeydownListener = this.onDOMKeydown.bind(this)
9
+
7
10
  if (this.element.dataset.value) {
8
11
  const option = this.selectTarget.querySelector(
9
12
  `[value=${this.element.dataset.value}]`,
@@ -23,12 +26,29 @@ export default class extends Controller {
23
26
  this.choices.removeChoice('')
24
27
  }
25
28
 
29
+ this.selectTarget.addEventListener(
30
+ 'showDropdown',
31
+ function () {
32
+ document.addEventListener('keydown', this.DOMKeydownListener)
33
+ }.bind(this),
34
+ false,
35
+ )
36
+
26
37
  this.selectTarget.addEventListener(
27
38
  'hideDropdown',
28
39
  function () {
29
40
  this.choices.containerOuter.element.focus()
41
+ document.removeEventListener('keydown', this.DOMKeydownListener)
30
42
  }.bind(this),
31
43
  false,
32
44
  )
33
45
  }
46
+
47
+ onDOMKeydown(event) {
48
+ const key = event.key
49
+
50
+ if (key === 'Tab') {
51
+ event.preventDefault()
52
+ }
53
+ }
34
54
  }
@@ -1,113 +1,145 @@
1
- import { Controller } from '@hotwired/stimulus'
1
+ import {
2
+ FOCUS_DELAY,
3
+ initFloatingUi,
4
+ showOverlay,
5
+ hideOverlay,
6
+ lockScroll,
7
+ unlockScroll,
8
+ } from '../utils'
2
9
  import { Calendar } from 'vanilla-calendar-pro'
10
+ import Inputmask from 'inputmask'
11
+ import PopoverController from './popover_controller'
3
12
  import dayjs from 'dayjs'
4
13
  import customParseFormat from 'dayjs/plugin/customParseFormat'
5
14
  import utc from 'dayjs/plugin/utc'
6
15
  dayjs.extend(customParseFormat)
7
16
  dayjs.extend(utc)
8
17
 
9
- export default class extends Controller {
10
- static targets = ['dateInput', 'hiddenInput', 'clearButton', 'calendarIcon']
18
+ export default class extends PopoverController {
19
+ static targets = [
20
+ 'trigger',
21
+ 'triggerText',
22
+ 'contentWrapper',
23
+ 'content',
24
+ 'input',
25
+ 'hiddenInput',
26
+ 'inputContainer',
27
+ 'calendar',
28
+ ]
29
+
30
+ static values = {
31
+ date: String,
32
+ }
11
33
 
12
34
  connect() {
13
- this.date = this.element.dataset.value
35
+ super.connect()
36
+
37
+ const date = this.element.dataset.value
14
38
  this.format = this.element.dataset.format
39
+
15
40
  const settings = this.getSettings()
16
41
  settings.type = 'default'
17
42
 
18
- if (this.date && dayjs(this.date).isValid()) {
19
- const dayjsDate = dayjs(this.date)
20
- const formattedDate = dayjsDate.format(this.format)
21
- this.dateInputTarget.value = formattedDate
22
- settings.selectedDates = [dayjsDate.format('YYYY-MM-DD')]
43
+ this.onClickDateListener = this.onClickDate.bind(this)
44
+
45
+ if (date && dayjs(date).isValid()) {
46
+ const dayjsDate = dayjs(date).format('YYYY-MM-DD')
47
+ settings.selectedDates = [dayjsDate]
48
+ this.dateValue = dayjsDate
23
49
  }
24
50
 
25
- const calendar = new Calendar(this.dateInputTarget, {
26
- inputMode: true,
51
+ this.calendar = new Calendar(this.calendarTarget, {
27
52
  enableJumpToSelectedDate: true,
28
53
  ...settings,
29
- onClickDate(self, event) {
30
- const date = self.context.selectedDates[0]
31
-
32
- const controllerElement = self.context.inputElement.closest(
33
- '[data-controller="shadcn-phlexcomponents--date-picker"]',
34
- )
35
-
36
- const hiddenInput = controllerElement.querySelector(
37
- '[data-shadcn-phlexcomponents--date-picker-target="hiddenInput"]',
38
- )
39
-
40
- if (date) {
41
- const formattedDate = dayjs(date).format(
42
- controllerElement.dataset.format,
43
- )
44
- self.context.inputElement.value = formattedDate
45
- controllerElement.dataset.hasValue = 'true'
46
- const utcDate = dayjs(date).utc().format()
47
- hiddenInput.value = utcDate
48
- } else {
49
- self.context.inputElement.value = ''
50
- controllerElement.dataset.hasValue = 'false'
51
- hiddenInput.value = ''
52
- }
53
- },
54
+ onClickDate: this.onClickDateListener,
54
55
  })
55
- calendar.init()
56
56
 
57
- this.calendar = calendar
57
+ this.calendar.init()
58
+
59
+ if (this.hasInputTarget) {
60
+ const im = new Inputmask(this.format.replace(/[^\/]/g, '9'), {
61
+ showMaskOnHover: false,
62
+ })
63
+ im.mask(this.inputTarget)
64
+ }
65
+
66
+ this.calendarTarget.removeAttribute('tabindex')
58
67
  }
59
68
 
60
69
  inputBlur() {
61
- const date = this.calendar.selectedDates[0]
70
+ let dateDisplay = ''
71
+ const date = this.calendar.context.selectedDates[0]
62
72
 
63
73
  if (date) {
64
- const formattedDate = dayjs(date).format(this.format)
65
- this.dateInputTarget.value = formattedDate
74
+ dateDisplay = dayjs(date).format(this.format)
66
75
  }
76
+
77
+ this.inputTarget.value = dateDisplay
78
+ this.inputContainerTarget.dataset.focus = false
67
79
  }
68
80
 
69
81
  changeDate(event) {
70
82
  const value = event.target.value
71
83
 
84
+ if (value.length === 0) {
85
+ this.calendar.set({
86
+ selectedDates: [],
87
+ })
88
+ this.dateValue = ''
89
+ }
90
+
72
91
  if (value.length > 0 && dayjs(value, this.format, true).isValid()) {
73
- const dayjsDate = dayjs(value, this.format)
92
+ const dayjsDate = dayjs(value, this.format).format('YYYY-MM-DD')
74
93
  this.calendar.set({
75
- selectedDates: [dayjsDate.format('YYYY-MM-DD')],
94
+ selectedDates: [dayjsDate],
76
95
  })
96
+ this.dateValue = dayjsDate
77
97
  }
78
98
  }
79
99
 
80
- closeCalendar(event) {
81
- const key = event.key
100
+ onOpen() {
101
+ setTimeout(() => {
102
+ this.focusCalendar()
103
+ }, FOCUS_DELAY * 1.5)
82
104
 
83
- if (key === 'Escape' || key === 'Tab') {
84
- this.calendar.hide()
105
+ this.cleanup = initFloatingUi(
106
+ this.hasInputTarget ? this.inputTarget : this.triggerTarget,
107
+ this.contentWrapperTarget,
108
+ 'bottom-start',
109
+ )
110
+
111
+ if (!this.contentTarget.dataset.width) {
112
+ const contentWidth = this.contentTarget.offsetWidth
113
+ this.contentTarget.dataset.width = contentWidth
114
+
115
+ this.contentTarget.style.maxWidth = `${contentWidth}px`
116
+ this.contentTarget.style.minWidth = `${contentWidth}px`
85
117
  }
118
+
119
+ if (window.innerWidth <= 640) {
120
+ lockScroll()
121
+ }
122
+ showOverlay('md:hidden')
86
123
  }
87
124
 
88
- clear() {
89
- this.dateInputTarget.value = ''
90
- this.hiddenInputTarget.value = ''
125
+ focusCalendar() {
126
+ const focusableElements = this.contentTarget.querySelectorAll(
127
+ 'button, [href], input:not([type="hidden"]), select, textarea, [tabindex]:not([tabindex="-1"])',
128
+ )
91
129
 
92
- this.calendar.set({
93
- selectedDates: [],
94
- })
130
+ const selectedElement = Array.from(focusableElements).find(
131
+ (e) => e.ariaSelected,
132
+ )
95
133
 
96
- this.element.dataset.hasValue = 'false'
97
- }
134
+ const currentElement = this.contentTarget.querySelector('[aria-current]')
98
135
 
99
- showClearButton() {
100
- if (this.element.dataset.hasValue === 'true') {
101
- this.clearButtonTarget.classList.remove('!hidden')
102
- this.calendarIconTarget.classList.add('hidden')
136
+ if (selectedElement) {
137
+ selectedElement.focus()
138
+ } else if (currentElement) {
139
+ currentElement.firstElementChild.focus()
103
140
  }
104
141
  }
105
142
 
106
- hideClearButton() {
107
- this.clearButtonTarget.classList.add('!hidden')
108
- this.calendarIconTarget.classList.remove('hidden')
109
- }
110
-
111
143
  getSettings() {
112
144
  try {
113
145
  return JSON.parse(this.element.dataset.settings)
@@ -115,4 +147,107 @@ export default class extends Controller {
115
147
  return {}
116
148
  }
117
149
  }
150
+
151
+ onDOMKeydown(event) {
152
+ if (!this.isOpen()) return
153
+
154
+ const key = event.key
155
+
156
+ const focusableElements = this.contentTarget.querySelectorAll(
157
+ 'button, [href], input:not([type="hidden"]), select, textarea, [tabindex]:not([tabindex="-1"])',
158
+ )
159
+
160
+ const firstElement = focusableElements[0]
161
+ const lastElement = focusableElements[focusableElements.length - 1]
162
+
163
+ if (key === 'Escape') {
164
+ this.close()
165
+ } else if (key === 'Tab') {
166
+ // If Shift + Tab pressed on first element, go to last element
167
+ if (event.shiftKey && document.activeElement === firstElement) {
168
+ event.preventDefault()
169
+ lastElement.focus()
170
+ }
171
+ // If Tab pressed on last element, go to first element
172
+ else if (!event.shiftKey && document.activeElement === lastElement) {
173
+ event.preventDefault()
174
+ firstElement.focus()
175
+ }
176
+ } else if (
177
+ ['ArrowUp', 'ArrowDown', 'ArrowRight', 'ArrowLeft'].includes(key) &&
178
+ document.activeElement != this.inputTarget
179
+ ) {
180
+ event.preventDefault()
181
+ }
182
+ }
183
+
184
+ onDOMClick(event) {
185
+ if (!this.isOpen()) return
186
+ if (this.element.contains(event.target)) return
187
+
188
+ // Fix bug with clicking/pressing on Month/Year button will cause popover to close
189
+ // Fix bug with clicking/pressing on Month/Year button will cause popover to close
190
+ if (
191
+ event.target.dataset.vcMonth ||
192
+ event.target.dataset.vcYear ||
193
+ event.target.dataset.vcYearsYear ||
194
+ event.target.dataset.vcMonthsMonth ||
195
+ event.target.dataset.vcArrow ||
196
+ event.target.dataset.vcGrid
197
+ )
198
+ return
199
+
200
+ this.close()
201
+ }
202
+
203
+ setContainerFocus() {
204
+ this.inputContainerTarget.dataset.focus = true
205
+ }
206
+
207
+ onClose() {
208
+ hideOverlay()
209
+ if (window.innerWidth <= 640) {
210
+ unlockScroll()
211
+ }
212
+ }
213
+
214
+ onClickDate(self, event) {
215
+ const date = self.context.selectedDates[0]
216
+
217
+ if (date) {
218
+ this.dateValue = date
219
+ this.close()
220
+ } else {
221
+ this.dateValue = ''
222
+ }
223
+ }
224
+
225
+ dateValueChanged(value) {
226
+ if (value && value.length > 0) {
227
+ const dayjsDate = dayjs(value)
228
+ const formattedDate = dayjsDate.format(this.format)
229
+
230
+ if (this.hasInputTarget) this.inputTarget.value = formattedDate
231
+ if (this.hasTriggerTextTarget) {
232
+ this.triggerTarget.dataset.hasValue = true
233
+ this.triggerTextTarget.textContent = formattedDate
234
+ }
235
+
236
+ this.hiddenInputTarget.value = dayjsDate.utc().format()
237
+ } else {
238
+ if (this.hasInputTarget) this.inputTarget.value = ''
239
+
240
+ if (this.hasTriggerTextTarget) {
241
+ this.triggerTarget.dataset.hasValue = false
242
+ if (this.triggerTarget.dataset.placeholder) {
243
+ this.triggerTextTarget.textContent =
244
+ this.triggerTarget.dataset.placeholder
245
+ } else {
246
+ this.triggerTextTarget.textContent = ''
247
+ }
248
+ }
249
+
250
+ this.hiddenInputTarget.value = ''
251
+ }
252
+ }
118
253
  }