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,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class TableCaption < Base
5
+ STYLES = "mt-4 text-sm text-muted-foreground".freeze
6
+
7
+ def view_template(&)
8
+ caption(**@attributes, &)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class TableCell < Base
5
+ STYLES = "p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]".freeze
6
+
7
+ def view_template(&)
8
+ td(**@attributes, &)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class TableFooter < Base
5
+ STYLES = "border-t bg-muted/50 font-medium [&>tr]:last:border-b-0".freeze
6
+
7
+ def view_template(&)
8
+ tfoot(**@attributes, &)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class TableHead < Base
5
+ STYLES = <<~HEREDOC
6
+ h-10 px-2 text-left align-middle font-medium text-muted-foreground
7
+ [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]
8
+ HEREDOC
9
+
10
+ def view_template(&)
11
+ th(**@attributes, &)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class TableHeader < Base
5
+ STYLES = "[&_tr]:border-b".freeze
6
+
7
+ def view_template(&)
8
+ thead(**@attributes, &)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class TableRow < Base
5
+ STYLES = "border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted".freeze
6
+
7
+ def view_template(&)
8
+ tr(**@attributes, &)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class Tabs < Base
5
+ def initialize(value: nil, dir: "ltr", aria_id: "tabs-#{SecureRandom.hex(5)}", **attributes)
6
+ @dir = dir
7
+ @value = value
8
+ @aria_id = aria_id
9
+ super(**attributes)
10
+ end
11
+
12
+ def view_template(&)
13
+ div(**@attributes, &)
14
+ end
15
+
16
+ def default_attributes
17
+ {
18
+ dir: @dir,
19
+ data: {
20
+ controller: "shadcn-phlexcomponents--tabs",
21
+ "shadcn-phlexcomponents--tabs-selected-value": @value
22
+ }
23
+ }
24
+ end
25
+
26
+ def list(**attributes, &)
27
+ TabsList(**attributes, &)
28
+ end
29
+
30
+ def trigger(**attributes, &)
31
+ TabsTrigger(aria_id: @aria_id, **attributes, &)
32
+ end
33
+
34
+ def content(**attributes, &)
35
+ TabsContent(aria_id: @aria_id, **attributes, &)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class TabsContent < Base
5
+ STYLES = <<~HEREDOC.freeze
6
+ mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2
7
+ focus-visible:ring-ring focus-visible:ring-offset-2 hidden
8
+ HEREDOC
9
+
10
+ def initialize(value: nil, aria_id: nil, **attributes)
11
+ @value = value
12
+ @aria_id = aria_id
13
+ super(**attributes)
14
+ end
15
+
16
+ def view_template(&)
17
+ div(**@attributes, &)
18
+ end
19
+
20
+ def default_attributes
21
+ {
22
+ id: "#{@aria_id}-content-#{@value}",
23
+ role: "tabpanel",
24
+ tabindex: "0",
25
+ aria: {
26
+ labelledby: "#{@aria_id}-trigger-#{@value}"
27
+ },
28
+ data: {
29
+ value: @value,
30
+ "shadcn-phlexcomponents--tabs-target": "content"
31
+ }
32
+ }
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class TabsList < Base
5
+ STYLES = <<~HEREDOC.freeze
6
+ inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground outline-none
7
+ HEREDOC
8
+
9
+ def view_template(&)
10
+ div(**@attributes, &)
11
+ end
12
+
13
+ def default_attributes
14
+ {
15
+ role: "tablist",
16
+ tabindex: "-1",
17
+ aria: {
18
+ orientation: "horizontal"
19
+ }
20
+ }
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class TabsTrigger < Base
5
+ STYLES = <<~HEREDOC.freeze
6
+ inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm
7
+ font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2
8
+ focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50
9
+ data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow
10
+ cursor-pointer
11
+ HEREDOC
12
+
13
+ def initialize(value: nil, aria_id: nil, **attributes)
14
+ @value = value
15
+ @aria_id = aria_id
16
+ super(**attributes)
17
+ end
18
+
19
+ def view_template(&)
20
+ button(**@attributes, &)
21
+ end
22
+
23
+ def default_attributes
24
+ {
25
+ id: "#{@aria_id}-trigger-#{@value}",
26
+ role: "tab",
27
+ tabindex: "-1",
28
+ aria: {
29
+ controls: "#{@aria_id}-content-#{@value}",
30
+ selected: false,
31
+ },
32
+ data: {
33
+ "shadcn-phlexcomponents--tabs-target": "trigger",
34
+ value: @value,
35
+ state: "inactive",
36
+ action: <<~HEREDOC,
37
+ click->shadcn-phlexcomponents--tabs#setActiveTab
38
+ keydown.left->shadcn-phlexcomponents--tabs#setActiveToPrev:prevent
39
+ keydown.right->shadcn-phlexcomponents--tabs#setActiveToNext:prevent
40
+ HEREDOC
41
+ }
42
+ }
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class Textarea < Base
5
+ STYLES = <<~HEREDOC
6
+ flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3
7
+ py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none
8
+ focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm
9
+ HEREDOC
10
+
11
+ def initialize(name: nil, id: nil, **attributes)
12
+ @name = name
13
+ @id = id || @name
14
+ super(**attributes)
15
+ end
16
+
17
+ def default_attributes
18
+ {
19
+ name: @name,
20
+ id: @id,
21
+ }
22
+ end
23
+
24
+ def view_template(&)
25
+ textarea(**@attributes, &)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class ThemeSwitcher < Base
5
+ def view_template
6
+ Button(variant: :ghost, size: :icon, **@attributes)do
7
+ icon("sun", class: "hidden dark:inline")
8
+ icon("moon", class: "inline dark:hidden")
9
+ end
10
+ end
11
+
12
+ def default_attributes
13
+ {
14
+ data: {
15
+ controller: "shadcn-phlexcomponents--theme-switcher",
16
+ action: "shadcn-phlexcomponents--theme-switcher#toggle",
17
+ },
18
+ }
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class Toast < Base
5
+ STYLES = <<~HEREDOC
6
+ group pointer-events-auto relative flex w-full items-center justify-between
7
+ space-x-2 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all
8
+ data-[state=open]:animate-in data-[state=closed]:animate-out
9
+ data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full
10
+ data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full
11
+ HEREDOC
12
+
13
+ CLOSE_BUTTON_STYLES = <<~HEREDOC
14
+ absolute right-1 top-1 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity
15
+ hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-1 group-hover:opacity-100
16
+ group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400
17
+ group-[.destructive]:focus:ring-offset-red-600 cursor-pointer
18
+ HEREDOC
19
+
20
+ VARIANTS = {
21
+ default: "border bg-background text-foreground",
22
+ destructive: "destructive group border-destructive bg-destructive text-destructive-foreground",
23
+ }.freeze
24
+
25
+ def initialize(variant: :default, duration: 5000, **attributes)
26
+ @variant = variant
27
+ @duration = duration
28
+ super(**attributes)
29
+ end
30
+
31
+ def title(**attributes, &)
32
+ ToastTitle(data: { title: ""}, **attributes, &)
33
+ end
34
+
35
+ def description(**attributes, &)
36
+ ToastDescription(data: { description: ""},**attributes, &)
37
+ end
38
+
39
+ def content(**attributes, &)
40
+ ToastContent(**attributes, &)
41
+ end
42
+
43
+ def action(**attributes, &)
44
+ ToastAction(variant: @variant, **attributes, &)
45
+ end
46
+
47
+ def action_to(name = nil, options = nil, html_options = nil, &block)
48
+ if block_given?
49
+ options ||= {}
50
+ options[:variant] = @variant
51
+ else
52
+ html_options ||= {}
53
+ html_options[:variant] = @variant
54
+ end
55
+
56
+ ToastActionTo(name, options, html_options, &block)
57
+ end
58
+
59
+ def default_styles
60
+ "#{STYLES} #{VARIANTS[@variant]}"
61
+ end
62
+
63
+ def default_attributes
64
+ {
65
+ role: "status",
66
+ tabindex: 0,
67
+ aria: {
68
+ live: "off",
69
+ atomic: "true",
70
+ },
71
+ data: {
72
+ duration: @duration,
73
+ state: "open",
74
+ controller: "shadcn-phlexcomponents--toast",
75
+ action: <<~HEREDOC
76
+ focus->shadcn-phlexcomponents--toast#cancelDismiss
77
+ blur->shadcn-phlexcomponents--toast#dismiss
78
+ mouseover->shadcn-phlexcomponents--toast#cancelDismiss
79
+ mouseout->shadcn-phlexcomponents--toast#dismiss
80
+ keydown.esc->shadcn-phlexcomponents--toast#close
81
+ HEREDOC
82
+ }
83
+ }
84
+ end
85
+
86
+ def view_template(&)
87
+ li(**@attributes) do
88
+ yield
89
+ button(type: "button",
90
+ class: CLOSE_BUTTON_STYLES,
91
+ data: {
92
+ action: "shadcn-phlexcomponents--toast#close",
93
+ }) do
94
+
95
+ icon("x", class: "size-4")
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class ToastAction < Base
5
+ STYLES = <<~HEREDOC
6
+ inline-flex h-8 shrink-0 items-center justify-center rounded-md border
7
+ bg-transparent px-3 text-sm font-medium transition-colors hover:bg-secondary
8
+ focus:outline-none focus:ring-1 focus:ring-ring disabled:pointer-events-none
9
+ disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30
10
+ group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground
11
+ group-[.destructive]:focus:ring-destructive cursor-pointer
12
+ HEREDOC
13
+
14
+ def initialize(as_child: false, **attributes)
15
+ @as_child = as_child
16
+ super(**attributes)
17
+ end
18
+
19
+ def view_template(&)
20
+ if @as_child
21
+ content = capture(&)
22
+ element = find_as_child(content.to_s)
23
+
24
+ vanish(&)
25
+
26
+ element_attributes = nokogiri_attributes_to_hash(element)
27
+ merged_attributes = mix(@attributes, element_attributes)
28
+ merged_attributes[:class] = TAILWIND_MERGER.merge("#{STYLES} #{element_attributes[:class]}")
29
+
30
+ send(element.name, **merged_attributes) do
31
+ sanitize_as_child(element.children.to_s)
32
+ end
33
+ else
34
+ button(**@attributes, &)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class ToastActionTo < ToastAction
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 view_template(&)
12
+ @html_options, @options = @options, @name if block_given?
13
+ @html_options ||= {}
14
+ @variant = @html_options.delete(:variant) || :default
15
+ @html_options = mix(default_attributes, @html_options)
16
+ @html_options[:class] = TAILWIND_MERGER.merge("#{default_styles} #{@html_options[:class]}")
17
+
18
+ if block_given?
19
+ button_to(@options, @html_options, &)
20
+ else
21
+ button_to(@name, @options, @html_options)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class ToastContainer < Base
5
+ STYLES = <<~HEREDOC
6
+ fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4
7
+ sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]
8
+ HEREDOC
9
+
10
+ def default_attributes
11
+ {
12
+ tabindex: -1,
13
+ data: {
14
+ controller: "shadcn-phlexcomponents--toast-container",
15
+ }
16
+ }
17
+ end
18
+
19
+ def view_template(&)
20
+ div(
21
+ role: "region",
22
+ tabindex: -1,
23
+ aria: {
24
+ label: "Notifications",
25
+ }
26
+ ) do
27
+ ol(**@attributes) do
28
+ template(data: { variant: "default" }) { toast(:default) }
29
+ template(data: { variant: "destructive" }) { toast(:destructive) }
30
+ yield
31
+ end
32
+ end
33
+ end
34
+
35
+ def toast(variant)
36
+ Toast(variant: variant) do |t|
37
+ t.content do
38
+ t.title { "" }
39
+ t.description { "" }
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class ToastContent < Base
5
+ STYLES = "grid gap-1"
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 ToastDescription < Base
5
+ STYLES = "text-sm opacity-90"
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 ToastTitle < Base
5
+ STYLES = "text-sm font-semibold [&+div]:text-xs"
6
+
7
+ def view_template(&)
8
+ div(**@attributes, &)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class Tooltip < Base
5
+ STYLES = "inline-block".freeze
6
+
7
+ def initialize(side: :top, aria_id: "tooltip-#{SecureRandom.hex(5)}", **attributes)
8
+ @side = side
9
+ @aria_id = aria_id
10
+ super(**attributes)
11
+ end
12
+
13
+ def trigger(**attributes, &)
14
+ render TooltipTrigger.new(aria_id: @aria_id, **attributes, &)
15
+ end
16
+
17
+ def content(**attributes, &)
18
+ render TooltipContent.new(side: @side, aria_id: @aria_id, **attributes, &)
19
+ end
20
+
21
+ def default_attributes
22
+ {
23
+ data: {
24
+ controller: "shadcn-phlexcomponents--tooltip",
25
+ side: @side
26
+ }
27
+ }
28
+ end
29
+
30
+ def view_template(&)
31
+ div(**@attributes, &)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class TooltipContent < Base
5
+ STYLES = <<~HEREDOC.freeze
6
+ z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground
7
+ animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0
8
+ data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2
9
+ data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2
10
+ HEREDOC
11
+
12
+ def initialize(side: :top, aria_id: nil, **attributes)
13
+ @side = side
14
+ @aria_id = aria_id
15
+ super(**attributes)
16
+ end
17
+
18
+ def view_template(&)
19
+ div(class: 'hidden fixed top-0 left-0 w-max z-50', data: { "shadcn-phlexcomponents--tooltip-target": "contentWrapper" }) do
20
+ div(**@attributes, &)
21
+
22
+ span(
23
+ id: "#{@aria_id}-content",
24
+ role: "tooltip",
25
+ class: "sr-only",
26
+ &
27
+ )
28
+ end
29
+ end
30
+
31
+ def default_attributes
32
+ {
33
+ tabindex: -1,
34
+ data: {
35
+ side: @side,
36
+ "shadcn-phlexcomponents--tooltip-target": "content",
37
+ action: "mouseover->shadcn-phlexcomponents--tooltip#clearCloseTimer mouseout->shadcn-phlexcomponents--tooltip#closeWithDelay"
38
+ }
39
+ }
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class TooltipTrigger < Base
5
+ def initialize(as_child: false, aria_id: nil, **attributes)
6
+ @as_child = as_child
7
+ @aria_id = aria_id
8
+ super(**attributes)
9
+ end
10
+
11
+ def view_template(&)
12
+ if @as_child
13
+ content = capture(&)
14
+ element = find_as_child(content.to_s)
15
+
16
+ vanish(&)
17
+ element_attributes = nokogiri_attributes_to_hash(element)
18
+ styles = TAILWIND_MERGER.merge("#{@attributes[:class]} #{element_attributes[:class]}")
19
+ merged_attributes = mix(@attributes, element_attributes)
20
+ merged_attributes[:class] = styles
21
+
22
+ send(element.name, **merged_attributes) do
23
+ sanitize_as_child(element.children.to_s)
24
+ end
25
+ else
26
+ div(**@attributes, &)
27
+ end
28
+ end
29
+
30
+ def default_attributes
31
+ {
32
+ id: @id,
33
+ role: "button",
34
+ aria: {
35
+ describedby: "#{@aria_id}-content"
36
+ },
37
+ data: {
38
+ as_child: @as_child.to_s,
39
+ state: "closed",
40
+ action: <<~HEREDOC,
41
+ click->shadcn-phlexcomponents--tooltip#toggle
42
+ mouseover->shadcn-phlexcomponents--tooltip#openWithDelay
43
+ mouseout->shadcn-phlexcomponents--tooltip#closeWithDelay
44
+ HEREDOC
45
+ "shadcn-phlexcomponents--tooltip-target": "trigger"
46
+ }
47
+ }
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ components_path = File.expand_path("../components", __dir__)
4
+ components_install_path = Rails.root.join("vendor/shadcn_phlexcomponents")
5
+ stimulus_controllers_path = File.expand_path("../../app/javascript/controllers", __dir__)
6
+ stimulus_controllers_install_path = Rails.root.join("app/javascript/controllers/shadcn_phlexcomponents")
7
+ tailwindcss_animate_path = File.expand_path("../../app/assets/tailwind/tailwindcss-animate.css", __dir__)
8
+ tailwindcss_animate_install_path = Rails.root.join("app/assets/tailwind/shadcn_phlexcomponents/tailwindcss-animate.css")
9
+
10
+ directory(components_path, components_install_path)
11
+ directory(stimulus_controllers_path, stimulus_controllers_install_path)
12
+ copy_file(tailwindcss_animate_path, tailwindcss_animate_install_path)