shadcn_phlexcomponents 0.1.0

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 (168) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +39 -0
  3. data/Rakefile +12 -0
  4. data/app/assets/tailwind/tailwindcss-animate.css +318 -0
  5. data/app/assets/tailwind/vanilla-calendar-pro.css +461 -0
  6. data/app/javascript/controllers/accordion_controller.js +133 -0
  7. data/app/javascript/controllers/alert_dialog_controller.js +157 -0
  8. data/app/javascript/controllers/avatar_controller.js +15 -0
  9. data/app/javascript/controllers/checkbox_controller.js +28 -0
  10. data/app/javascript/controllers/collapsible_controller.js +35 -0
  11. data/app/javascript/controllers/combobox_controller.js +291 -0
  12. data/app/javascript/controllers/datepicker_controller.js +47 -0
  13. data/app/javascript/controllers/dialog_controller.js +159 -0
  14. data/app/javascript/controllers/dropdown_menu_controller.js +193 -0
  15. data/app/javascript/controllers/hover_card_controller.js +135 -0
  16. data/app/javascript/controllers/loading_button_controller.js +15 -0
  17. data/app/javascript/controllers/popover_controller.js +124 -0
  18. data/app/javascript/controllers/progress_controller.js +14 -0
  19. data/app/javascript/controllers/radio_group_controller.js +90 -0
  20. data/app/javascript/controllers/select_controller.js +294 -0
  21. data/app/javascript/controllers/sheet_controller.js +159 -0
  22. data/app/javascript/controllers/sidebar_controller.js +36 -0
  23. data/app/javascript/controllers/sidebar_trigger_controller.js +15 -0
  24. data/app/javascript/controllers/switch_controller.js +24 -0
  25. data/app/javascript/controllers/tabs_controller.js +73 -0
  26. data/app/javascript/controllers/theme_switcher_controller.js +32 -0
  27. data/app/javascript/controllers/toast_container_controller.js +22 -0
  28. data/app/javascript/controllers/toast_controller.js +45 -0
  29. data/app/javascript/controllers/tooltip_controller.js +135 -0
  30. data/lib/components/accordion.rb +38 -0
  31. data/lib/components/accordion_content.rb +28 -0
  32. data/lib/components/accordion_item.rb +26 -0
  33. data/lib/components/accordion_trigger.rb +45 -0
  34. data/lib/components/alert.rb +40 -0
  35. data/lib/components/alert_description.rb +11 -0
  36. data/lib/components/alert_dialog.rb +60 -0
  37. data/lib/components/alert_dialog_action.rb +22 -0
  38. data/lib/components/alert_dialog_action_to.rb +37 -0
  39. data/lib/components/alert_dialog_cancel.rb +22 -0
  40. data/lib/components/alert_dialog_content.rb +40 -0
  41. data/lib/components/alert_dialog_description.rb +22 -0
  42. data/lib/components/alert_dialog_footer.rb +11 -0
  43. data/lib/components/alert_dialog_header.rb +11 -0
  44. data/lib/components/alert_dialog_title.rb +22 -0
  45. data/lib/components/alert_dialog_trigger.rb +50 -0
  46. data/lib/components/alert_title.rb +11 -0
  47. data/lib/components/aspect_ratio.rb +19 -0
  48. data/lib/components/avatar.rb +31 -0
  49. data/lib/components/avatar_fallback.rb +21 -0
  50. data/lib/components/avatar_image.rb +20 -0
  51. data/lib/components/badge.rb +36 -0
  52. data/lib/components/base.rb +108 -0
  53. data/lib/components/breadcrumb.rb +51 -0
  54. data/lib/components/breadcrumb_ellipsis.rb +23 -0
  55. data/lib/components/breadcrumb_item.rb +11 -0
  56. data/lib/components/breadcrumb_link.rb +7 -0
  57. data/lib/components/breadcrumb_page.rb +21 -0
  58. data/lib/components/breadcrumb_separator.rb +26 -0
  59. data/lib/components/button.rb +53 -0
  60. data/lib/components/card.rb +31 -0
  61. data/lib/components/card_content.rb +11 -0
  62. data/lib/components/card_description.rb +11 -0
  63. data/lib/components/card_footer.rb +11 -0
  64. data/lib/components/card_header.rb +11 -0
  65. data/lib/components/card_title.rb +11 -0
  66. data/lib/components/checkbox.rb +65 -0
  67. data/lib/components/checkbox_group.rb +48 -0
  68. data/lib/components/collapsible.rb +32 -0
  69. data/lib/components/collapsible_content.rb +25 -0
  70. data/lib/components/collapsible_trigger.rb +50 -0
  71. data/lib/components/datepicker.rb +38 -0
  72. data/lib/components/dialog.rb +52 -0
  73. data/lib/components/dialog_close.rb +42 -0
  74. data/lib/components/dialog_content.rb +54 -0
  75. data/lib/components/dialog_description.rb +22 -0
  76. data/lib/components/dialog_footer.rb +11 -0
  77. data/lib/components/dialog_header.rb +11 -0
  78. data/lib/components/dialog_title.rb +22 -0
  79. data/lib/components/dialog_trigger.rb +50 -0
  80. data/lib/components/dropdown_menu.rb +50 -0
  81. data/lib/components/dropdown_menu_content.rb +49 -0
  82. data/lib/components/dropdown_menu_item.rb +57 -0
  83. data/lib/components/dropdown_menu_item_to.rb +25 -0
  84. data/lib/components/dropdown_menu_label.rb +12 -0
  85. data/lib/components/dropdown_menu_separator.rb +20 -0
  86. data/lib/components/dropdown_menu_trigger.rb +58 -0
  87. data/lib/components/hover_card.rb +33 -0
  88. data/lib/components/hover_card_content.rb +36 -0
  89. data/lib/components/hover_card_trigger.rb +50 -0
  90. data/lib/components/input.rb +32 -0
  91. data/lib/components/label.rb +15 -0
  92. data/lib/components/link.rb +26 -0
  93. data/lib/components/loading_button.rb +21 -0
  94. data/lib/components/pagination.rb +38 -0
  95. data/lib/components/pagination_ellipsis.rb +24 -0
  96. data/lib/components/pagination_link.rb +34 -0
  97. data/lib/components/pagination_next.rb +32 -0
  98. data/lib/components/pagination_previous.rb +32 -0
  99. data/lib/components/popover.rb +35 -0
  100. data/lib/components/popover_content.rb +37 -0
  101. data/lib/components/popover_trigger.rb +52 -0
  102. data/lib/components/progress.rb +37 -0
  103. data/lib/components/radio_group.rb +62 -0
  104. data/lib/components/radio_group_item.rb +66 -0
  105. data/lib/components/select.rb +189 -0
  106. data/lib/components/select_content.rb +59 -0
  107. data/lib/components/select_group.rb +23 -0
  108. data/lib/components/select_item.rb +58 -0
  109. data/lib/components/select_label.rb +23 -0
  110. data/lib/components/select_trigger.rb +54 -0
  111. data/lib/components/separator.rb +29 -0
  112. data/lib/components/sheet.rb +53 -0
  113. data/lib/components/sheet_close.rb +42 -0
  114. data/lib/components/sheet_content.rb +67 -0
  115. data/lib/components/sheet_description.rb +22 -0
  116. data/lib/components/sheet_footer.rb +11 -0
  117. data/lib/components/sheet_header.rb +11 -0
  118. data/lib/components/sheet_title.rb +22 -0
  119. data/lib/components/sheet_trigger.rb +50 -0
  120. data/lib/components/sidebar.rb +103 -0
  121. data/lib/components/sidebar_container.rb +11 -0
  122. data/lib/components/sidebar_content.rb +11 -0
  123. data/lib/components/sidebar_footer.rb +11 -0
  124. data/lib/components/sidebar_group.rb +11 -0
  125. data/lib/components/sidebar_group_content.rb +11 -0
  126. data/lib/components/sidebar_group_label.rb +16 -0
  127. data/lib/components/sidebar_header.rb +11 -0
  128. data/lib/components/sidebar_inset.rb +15 -0
  129. data/lib/components/sidebar_menu.rb +11 -0
  130. data/lib/components/sidebar_menu_button.rb +61 -0
  131. data/lib/components/sidebar_menu_item.rb +9 -0
  132. data/lib/components/sidebar_menu_sub.rb +14 -0
  133. data/lib/components/sidebar_menu_sub_button.rb +48 -0
  134. data/lib/components/sidebar_menu_sub_item.rb +9 -0
  135. data/lib/components/sidebar_trigger.rb +40 -0
  136. data/lib/components/skeleton.rb +11 -0
  137. data/lib/components/switch.rb +65 -0
  138. data/lib/components/table.rb +73 -0
  139. data/lib/components/table_body.rb +11 -0
  140. data/lib/components/table_caption.rb +11 -0
  141. data/lib/components/table_cell.rb +11 -0
  142. data/lib/components/table_footer.rb +11 -0
  143. data/lib/components/table_head.rb +14 -0
  144. data/lib/components/table_header.rb +11 -0
  145. data/lib/components/table_row.rb +11 -0
  146. data/lib/components/tabs.rb +38 -0
  147. data/lib/components/tabs_content.rb +35 -0
  148. data/lib/components/tabs_list.rb +23 -0
  149. data/lib/components/tabs_trigger.rb +45 -0
  150. data/lib/components/textarea.rb +28 -0
  151. data/lib/components/theme_switcher.rb +21 -0
  152. data/lib/components/toast.rb +100 -0
  153. data/lib/components/toast_action.rb +38 -0
  154. data/lib/components/toast_action_to.rb +25 -0
  155. data/lib/components/toast_container.rb +44 -0
  156. data/lib/components/toast_content.rb +11 -0
  157. data/lib/components/toast_description.rb +11 -0
  158. data/lib/components/toast_title.rb +11 -0
  159. data/lib/components/tooltip.rb +34 -0
  160. data/lib/components/tooltip_content.rb +42 -0
  161. data/lib/components/tooltip_trigger.rb +50 -0
  162. data/lib/install/install_shadcn_phlexcomponents.rb +12 -0
  163. data/lib/shadcn_phlexcomponents/alias.rb +132 -0
  164. data/lib/shadcn_phlexcomponents/engine.rb +11 -0
  165. data/lib/shadcn_phlexcomponents/version.rb +5 -0
  166. data/lib/shadcn_phlexcomponents.rb +9 -0
  167. data/lib/tasks/install.rake +10 -0
  168. metadata +264 -0
@@ -0,0 +1,32 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+
3
+ export default class extends Controller {
4
+ initialize() {
5
+ document.documentElement.classList.toggle(
6
+ 'dark',
7
+ localStorage.theme === 'dark' ||
8
+ (!('theme' in localStorage) &&
9
+ window.matchMedia('(prefers-color-scheme: dark)').matches),
10
+ )
11
+ }
12
+
13
+ toggle() {
14
+ if (document.documentElement.classList.contains('dark')) {
15
+ localStorage.theme = 'light'
16
+ document.documentElement.classList.remove('dark')
17
+ } else {
18
+ localStorage.theme = 'dark'
19
+ document.documentElement.classList.add('dark')
20
+ }
21
+ }
22
+
23
+ setLightMode() {
24
+ localStorage.theme = 'light'
25
+ document.documentElement.classList.remove('dark')
26
+ }
27
+
28
+ setDarkMode() {
29
+ localStorage.theme = 'dark'
30
+ document.documentElement.classList.add('dark')
31
+ }
32
+ }
@@ -0,0 +1,22 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+
3
+ export default class extends Controller {
4
+ add({ title, description, variant = 'default' }) {
5
+ const template =
6
+ variant === 'default'
7
+ ? this.element.querySelector('[data-variant="default"]')
8
+ : this.element.querySelector('[data-variant="destructive"]')
9
+
10
+ const clone = template.content.cloneNode(true)
11
+
12
+ if (title) {
13
+ clone.querySelector('[data-title]').textContent = title
14
+ }
15
+
16
+ if (description) {
17
+ clone.querySelector('[data-description]').textContent = description
18
+ }
19
+
20
+ this.element.append(clone)
21
+ }
22
+ }
@@ -0,0 +1,45 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+
3
+ export default class extends Controller {
4
+ connect() {
5
+ this.focusableElements = this.element.querySelectorAll('button')
6
+ this.duration = Number(this.element.dataset.duration)
7
+
8
+ this.focusableElements.forEach((el) => {
9
+ el.addEventListener('focus', () => {
10
+ this.cancelDismiss()
11
+ })
12
+ el.addEventListener('blur', () => {
13
+ this.dismiss()
14
+ })
15
+ })
16
+
17
+ this.dismiss()
18
+ }
19
+
20
+ cancelDismiss() {
21
+ window.clearTimeout(this.timer)
22
+ }
23
+
24
+ close() {
25
+ this.element.dataset.state = 'closed'
26
+
27
+ setTimeout(() => {
28
+ this.element.remove()
29
+ }, 100)
30
+ }
31
+
32
+ dismiss(event) {
33
+ if (event && event.type === 'mouseout') {
34
+ if (this.element.contains(document.activeElement)) {
35
+ return
36
+ }
37
+ }
38
+
39
+ if (this.duration > 0) {
40
+ this.timer = setTimeout(() => {
41
+ this.close()
42
+ }, this.duration)
43
+ }
44
+ }
45
+ }
@@ -0,0 +1,135 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+ import {
3
+ computePosition,
4
+ flip,
5
+ shift,
6
+ offset,
7
+ autoUpdate,
8
+ } from '@floating-ui/dom'
9
+
10
+ export default class extends Controller {
11
+ static targets = ['trigger', 'contentWrapper', 'content']
12
+
13
+ connect() {
14
+ this.DOMClickListener = this.onDOMClick.bind(this)
15
+ this.DOMKeydownListener = this.onDOMKeydown.bind(this)
16
+
17
+ if (this.triggerTarget.dataset.asChild === 'false') {
18
+ this.triggerTarget.firstElementChild.addEventListener('focus', () => {
19
+ this.open()
20
+ })
21
+
22
+ this.triggerTarget.firstElementChild.addEventListener('blur', () => {
23
+ this.close()
24
+ })
25
+ } else {
26
+ this.triggerTarget.addEventListener('focus', () => {
27
+ this.open()
28
+ })
29
+
30
+ this.triggerTarget.addEventListener('blur', () => {
31
+ this.close()
32
+ })
33
+ }
34
+ }
35
+
36
+ toggle() {
37
+ if (this.isOpen()) {
38
+ this.close()
39
+ } else {
40
+ this.openWithDelay()
41
+ }
42
+ }
43
+
44
+ isOpen() {
45
+ return this.triggerTarget.dataset.state === 'open'
46
+ }
47
+
48
+ open() {
49
+ this.contentWrapperTarget.classList.remove('hidden')
50
+ this.triggerTarget.dataset.state = 'open'
51
+ this.contentTarget.dataset.state = 'open'
52
+ this.setupEventListeners()
53
+
54
+ this.cleanup = autoUpdate(
55
+ this.triggerTarget,
56
+ this.contentWrapperTarget,
57
+ () => {
58
+ computePosition(this.triggerTarget, this.contentWrapperTarget, {
59
+ placement: this.element.dataset.side,
60
+ strategy: 'fixed',
61
+ middleware: [flip(), shift(), offset(4)],
62
+ }).then(({ x, y }) => {
63
+ Object.assign(this.contentWrapperTarget.style, {
64
+ left: `${x}px`,
65
+ top: `${y}px`,
66
+ })
67
+ })
68
+ },
69
+ )
70
+ }
71
+
72
+ close() {
73
+ if (!this.isOpen()) return
74
+
75
+ this.contentTarget.dataset.state = 'closed'
76
+ this.triggerTarget.dataset.state = 'closed'
77
+ this.cleanup()
78
+ this.cleanupEventListeners()
79
+
80
+ setTimeout(() => {
81
+ this.contentWrapperTarget.classList.add('hidden')
82
+ }, 100)
83
+ }
84
+
85
+ clearOpenTimer() {
86
+ window.clearTimeout(this.openTimer)
87
+ }
88
+
89
+ clearCloseTimer() {
90
+ window.clearTimeout(this.closeTimer)
91
+ }
92
+
93
+ openWithDelay() {
94
+ this.clearCloseTimer()
95
+
96
+ this.openTimer = setTimeout(() => {
97
+ this.open()
98
+ }, 300)
99
+ }
100
+
101
+ closeWithDelay() {
102
+ window.clearTimeout(this.openTimer)
103
+
104
+ this.closeTimer = setTimeout(() => {
105
+ this.close()
106
+ }, 150)
107
+ }
108
+
109
+ // Global listeners
110
+ onDOMClick(event) {
111
+ if (!this.isOpen()) return
112
+ if (this.element.contains(event.target)) return
113
+
114
+ this.close()
115
+ }
116
+
117
+ onDOMKeydown(event) {
118
+ if (!this.isOpen()) return
119
+ const key = event.key
120
+
121
+ if (key === 'Escape') {
122
+ this.close()
123
+ }
124
+ }
125
+
126
+ setupEventListeners() {
127
+ document.addEventListener('click', this.DOMClickListener)
128
+ document.addEventListener('keydown', this.DOMKeydownListener)
129
+ }
130
+
131
+ cleanupEventListeners() {
132
+ document.removeEventListener('click', this.DOMClickListener)
133
+ document.removeEventListener('keydown', this.DOMKeydownListener)
134
+ }
135
+ }
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class Accordion < Base
5
+ def initialize(value: nil, multiple: false, aria_id: "accordion-#{SecureRandom.hex(5)}", **attributes)
6
+ @multiple = multiple
7
+ @value = value && value.is_a?(String) ? [ value ] : value
8
+ @aria_id = aria_id
9
+ super(**attributes)
10
+ end
11
+
12
+ def item(**attributes, &)
13
+ AccordionItem(**attributes, &)
14
+ end
15
+
16
+ def trigger(**attributes, &)
17
+ AccordionTrigger(aria_id: @aria_id, **attributes, &)
18
+ end
19
+
20
+ def content(**attributes, &)
21
+ AccordionContent(aria_id: @aria_id, **attributes, &)
22
+ end
23
+
24
+ def default_attributes
25
+ {
26
+ data: {
27
+ value: (@value || []).to_json,
28
+ multiple: @multiple.to_s,
29
+ controller: "shadcn-phlexcomponents--accordion"
30
+ }
31
+ }
32
+ end
33
+
34
+ def view_template(&)
35
+ div(**@attributes, &)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class AccordionContent < Base
5
+ STYLES = "pb-4 pt-0"
6
+
7
+ def initialize(aria_id: :nil, **attributes)
8
+ @aria_id = aria_id
9
+ super(**attributes)
10
+ end
11
+
12
+ def view_template(&)
13
+ div(class: "overflow-hidden text-sm data-[state=closed]:animate-accordion-up
14
+ data-[state=open]:animate-accordion-down hidden",
15
+ id: "#{@aria_id}-content",
16
+ role: "region",
17
+ aria: {
18
+ labelledby: "#{@aria_id}-trigger"
19
+ },
20
+ data: {
21
+ state: "closed",
22
+ "shadcn-phlexcomponents--accordion-target": "content"
23
+ }) do
24
+ div(**@attributes, &)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class AccordionItem < Base
5
+ STYLES = "border-b"
6
+
7
+ def initialize(value:, **attributes)
8
+ @value = value
9
+ super(**attributes)
10
+ end
11
+
12
+ def default_attributes
13
+ {
14
+ data: {
15
+ state: "closed",
16
+ value: @value,
17
+ "shadcn-phlexcomponents--accordion-target": "item"
18
+ }
19
+ }
20
+ end
21
+
22
+ def view_template(&)
23
+ div(**@attributes, &)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class AccordionTrigger < Base
5
+ STYLES = <<~HEREDOC
6
+ flex flex-1 items-center justify-between py-4 text-sm font-medium cursor-pointer
7
+ transition-all hover:underline text-left [&[data-state=open]>svg]:rotate-180
8
+ HEREDOC
9
+
10
+ def initialize(aria_id: nil, **attributes)
11
+ @aria_id = aria_id
12
+ super(**attributes)
13
+ end
14
+
15
+ def default_attributes
16
+ {
17
+ type: "button",
18
+ id: "#{@aria_id}-trigger",
19
+ aria: {
20
+ controls: "#{@aria_id}-content",
21
+ expanded: "false"
22
+ },
23
+ data: {
24
+ state: "closed",
25
+ "shadcn-phlexcomponents--accordion-target": "trigger",
26
+ action: <<~HEREDOC
27
+ click->shadcn-phlexcomponents--accordion#toggleItem
28
+ keydown.up->shadcn-phlexcomponents--accordion#focusPrev:prevent
29
+ keydown.down->shadcn-phlexcomponents--accordion#focusNext:prevent
30
+ HEREDOC
31
+ }
32
+ }
33
+ end
34
+
35
+ def view_template(&)
36
+ h3(class: "flex") do
37
+ button(**@attributes) do
38
+ yield
39
+
40
+ icon("chevron-down", class: "size-4 shrink-0 text-muted-foreground transition-transform duration-200")
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class Alert < Base
5
+ STYLES = <<~HEREDOC
6
+ relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px]
7
+ [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7
8
+ HEREDOC
9
+
10
+ VARIANTS = {
11
+ default: "bg-background text-foreground",
12
+ destructive: "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
13
+ }.freeze
14
+
15
+ def initialize(variant: :default, **attributes)
16
+ @variant = variant
17
+ super(**attributes)
18
+ end
19
+
20
+ def title(**attributes, &)
21
+ AlertTitle(**attributes, &)
22
+ end
23
+
24
+ def description(**attributes, &)
25
+ AlertDescription(**attributes, &)
26
+ end
27
+
28
+ def default_attributes
29
+ { role: "alert" }
30
+ end
31
+
32
+ def default_styles
33
+ "#{STYLES} #{VARIANTS[@variant]}"
34
+ end
35
+
36
+ def view_template(&)
37
+ div(**@attributes, &)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class AlertDescription < Base
5
+ STYLES = "text-sm [&_p]:leading-relaxed"
6
+
7
+ def view_template(&)
8
+ div(**@attributes, &)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class AlertDialog < Base
5
+ STYLES = "inline-block"
6
+
7
+ def initialize(aria_id: "alert-dialog-#{SecureRandom.hex(5)}", **attributes)
8
+ @aria_id = aria_id
9
+ super(**attributes)
10
+ end
11
+
12
+ def trigger(**attributes, &)
13
+ AlertDialogTrigger(aria_id: @aria_id, **attributes, &)
14
+ end
15
+
16
+ def content(**attributes, &)
17
+ AlertDialogContent(aria_id: @aria_id, **attributes, &)
18
+ end
19
+
20
+ def header(**attributes, &)
21
+ AlertDialogHeader(**attributes, &)
22
+ end
23
+
24
+ def title(**attributes, &)
25
+ AlertDialogTitle(aria_id: @aria_id, **attributes, &)
26
+ end
27
+
28
+ def description(**attributes, &)
29
+ AlertDialogDescription(aria_id: @aria_id, **attributes, &)
30
+ end
31
+
32
+ def footer(**attributes, &)
33
+ AlertDialogFooter(**attributes, &)
34
+ end
35
+
36
+ def cancel(**attributes, &)
37
+ AlertDialogCancel(**attributes, &)
38
+ end
39
+
40
+ def action(**attributes, &)
41
+ AlertDialogAction(**attributes, &)
42
+ end
43
+
44
+ def action_to(name = nil, options = nil, html_options = nil, &block)
45
+ AlertDialogActionTo(name, options, html_options, &block)
46
+ end
47
+
48
+ def default_attributes
49
+ {
50
+ data: {
51
+ controller: "shadcn-phlexcomponents--alert-dialog",
52
+ },
53
+ }
54
+ end
55
+
56
+ def view_template(&)
57
+ div(**@attributes, &)
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class AlertDialogAction < Base
5
+ def initialize(variant: :primary, **attributes)
6
+ @variant = variant
7
+ super(**attributes)
8
+ end
9
+
10
+ def default_attributes
11
+ {
12
+ data: {
13
+ action: "click->shadcn-phlexcomponents--alert-dialog#close",
14
+ },
15
+ }
16
+ end
17
+
18
+ def view_template(&)
19
+ Button(variant: @variant, **@attributes, &)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class AlertDialogActionTo < Base
5
+ def initialize(name = nil, options = nil, html_options = nil)
6
+ @name = name
7
+ @options = options
8
+ @html_options = html_options
9
+ end
10
+
11
+ def default_attributes
12
+ {
13
+ data: {
14
+ action: "click->shadcn-phlexcomponents--alert-dialog#close",
15
+ },
16
+ }
17
+ end
18
+
19
+ def default_styles
20
+ Button.default_styles(variant: @variant, size: :default)
21
+ end
22
+
23
+ def view_template(&)
24
+ @html_options, @options = @options, @name if block_given?
25
+ @html_options ||= {}
26
+ @variant = @html_options.delete(:variant) || :primary
27
+ @html_options = mix(default_attributes, @html_options)
28
+ @html_options[:class] = TAILWIND_MERGER.merge("#{default_styles} #{@html_options[:class]}")
29
+
30
+ if block_given?
31
+ button_to(@options, @html_options, &)
32
+ else
33
+ button_to(@name, @options, @html_options)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class AlertDialogCancel < Base
5
+ def initialize(variant: :outline, **attributes)
6
+ @variant = variant
7
+ super(**attributes)
8
+ end
9
+
10
+ def default_attributes
11
+ {
12
+ data: {
13
+ action: "click->shadcn-phlexcomponents--alert-dialog#close",
14
+ },
15
+ }
16
+ end
17
+
18
+ def view_template(&)
19
+ Button(variant: @variant, **@attributes, &)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class AlertDialogContent < Base
5
+ STYLES = <<~HEREDOC
6
+ fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%]
7
+ translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200
8
+ data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0
9
+ data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95
10
+ data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%]
11
+ data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg
12
+ HEREDOC
13
+
14
+ def initialize(aria_id: nil, **attributes)
15
+ @aria_id = aria_id
16
+ super(**attributes)
17
+ end
18
+
19
+ def default_attributes
20
+ {
21
+ id: "#{@aria_id}-content",
22
+ tabindex: -1,
23
+ role: "alertdialog",
24
+ aria: {
25
+ describedby: "#{@aria_id}-description",
26
+ labelledby: "#{@aria_id}-title",
27
+ },
28
+ data: {
29
+ state: "closed",
30
+ "shadcn-phlexcomponents--alert-dialog-target": "content",
31
+ },
32
+ }
33
+ end
34
+
35
+ def view_template(&)
36
+ @class = @attributes.delete(:class)
37
+ div(class: "#{@class} hidden", **@attributes, &)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class AlertDialogDescription < Base
5
+ STYLES = "text-sm text-muted-foreground"
6
+
7
+ def initialize(aria_id:, **attributes)
8
+ @aria_id = aria_id
9
+ super(**attributes)
10
+ end
11
+
12
+ def default_attributes
13
+ {
14
+ id: "#{@aria_id}-description",
15
+ }
16
+ end
17
+
18
+ def view_template(&)
19
+ p(**@attributes, &)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class AlertDialogFooter < Base
5
+ STYLES = "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2"
6
+
7
+ def view_template(&)
8
+ div(**@attributes, &)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class AlertDialogHeader < Base
5
+ STYLES = "flex flex-col space-y-2 text-center sm:text-left"
6
+
7
+ def view_template(&)
8
+ div(**@attributes, &)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class AlertDialogTitle < Base
5
+ STYLES = "text-lg font-semibold"
6
+
7
+ def initialize(aria_id:, **attributes)
8
+ @aria_id = aria_id
9
+ super(**attributes)
10
+ end
11
+
12
+ def default_attributes
13
+ {
14
+ id: "#{@aria_id}-title",
15
+ }
16
+ end
17
+
18
+ def view_template(&)
19
+ h2(**@attributes, &)
20
+ end
21
+ end
22
+ end