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,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+
5
+ class DropdownMenuTrigger < Base
6
+ def initialize(as_child: false, aria_id: nil, **attributes)
7
+ @as_child = as_child
8
+ @aria_id = aria_id
9
+ super(**attributes)
10
+ end
11
+
12
+ def view_template(&)
13
+ if @as_child
14
+ content = capture(&)
15
+ element = find_as_child(content.to_s)
16
+
17
+ vanish(&)
18
+ element_attributes = nokogiri_attributes_to_hash(element)
19
+ styles = TAILWIND_MERGER.merge("#{@attributes[:class]} #{element_attributes[:class]}")
20
+ merged_attributes = mix(@attributes, element_attributes)
21
+ merged_attributes[:class] = styles
22
+
23
+ if element.name == "button"
24
+ merged_attributes.delete(:role)
25
+ end
26
+
27
+ send(element.name, **merged_attributes) do
28
+ sanitize_as_child(element.children.to_s)
29
+ end
30
+ else
31
+ div(**@attributes, &)
32
+ end
33
+ end
34
+
35
+ def default_attributes
36
+ {
37
+ id: "#{@aria_id}-trigger",
38
+ role: "button",
39
+ aria: {
40
+ haspopup: "menu",
41
+ expanded: false,
42
+ controls: "#{@aria_id}-content"
43
+ },
44
+ data: {
45
+ state: "closed",
46
+ as_child: @as_child.to_s,
47
+ action: <<~HEREDOC,
48
+ click->shadcn-phlexcomponents--dropdown-menu#toggle
49
+ keydown.space->shadcn-phlexcomponents--dropdown-menu#toggle
50
+ keydown.enter->shadcn-phlexcomponents--dropdown-menu#toggle
51
+ keydown.down->shadcn-phlexcomponents--dropdown-menu#toggle:prevent
52
+ HEREDOC
53
+ "shadcn-phlexcomponents--dropdown-menu-target": "trigger"
54
+ }
55
+ }
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class HoverCard < Base
5
+ STYLES = "inline-block".freeze
6
+
7
+ def initialize(side: :bottom, **attributes)
8
+ @side = side
9
+ super(**attributes)
10
+ end
11
+
12
+ def content(**attributes, &)
13
+ HoverCardContent(**attributes, &)
14
+ end
15
+
16
+ def trigger(**attributes, &)
17
+ HoverCardTrigger(side: @side, **attributes, &)
18
+ end
19
+
20
+ def default_attributes
21
+ {
22
+ data: {
23
+ controller: "shadcn-phlexcomponents--hover-card",
24
+ side: @side
25
+ }
26
+ }
27
+ end
28
+
29
+ def view_template(&)
30
+ div(**@attributes, &)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class HoverCardContent < Base
5
+ STYLES = <<~HEREDOC.freeze
6
+ z-50 rounded-md border w-64 bg-popover p-4 text-popover-foreground shadow-md outline-none
7
+ data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0
8
+ data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95
9
+ data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2
10
+ data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2
11
+ HEREDOC
12
+
13
+ def initialize(side: :bottom, **attributes)
14
+ @side = side
15
+ super(**attributes)
16
+ end
17
+
18
+
19
+ def view_template(&)
20
+ div(class: 'hidden fixed top-0 left-0 w-max z-50', data: { "shadcn-phlexcomponents--hover-card-target": "contentWrapper" }) do
21
+ div(**@attributes, &)
22
+ end
23
+ end
24
+
25
+ def default_attributes
26
+ {
27
+ tabindex: -1,
28
+ data: {
29
+ side: @side,
30
+ "shadcn-phlexcomponents--hover-card-target": "content",
31
+ action: "mouseover->shadcn-phlexcomponents--hover-card#clearCloseTimer mouseout->shadcn-phlexcomponents--hover-card#closeWithDelay"
32
+ }
33
+ }
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class HoverCardTrigger < Base
5
+ def initialize(as_child: false, **attributes)
6
+ @as_child = as_child
7
+ super(**attributes)
8
+ end
9
+
10
+ def view_template(&)
11
+ if @as_child
12
+ content = capture(&)
13
+ element = find_as_child(content.to_s)
14
+
15
+ vanish(&)
16
+ element_attributes = nokogiri_attributes_to_hash(element)
17
+ styles = TAILWIND_MERGER.merge("#{@attributes[:class]} #{element_attributes[:class]}")
18
+ merged_attributes = mix(@attributes, element_attributes)
19
+ merged_attributes[:class] = styles
20
+
21
+ if element.name == "button"
22
+ merged_attributes.delete(:role)
23
+ end
24
+
25
+ send(element.name, **merged_attributes) do
26
+ sanitize_as_child(element.children.to_s)
27
+ end
28
+ else
29
+ div(**@attributes, &)
30
+ end
31
+ end
32
+
33
+ def default_attributes
34
+ {
35
+ id: @id,
36
+ role: "button",
37
+ data: {
38
+ state: "closed",
39
+ as_child: @as_child.to_s,
40
+ action: <<~HEREDOC,
41
+ click->shadcn-phlexcomponents--hover-card#toggle
42
+ mouseover->shadcn-phlexcomponents--hover-card#openWithDelay
43
+ mouseout->shadcn-phlexcomponents--hover-card#closeWithDelay
44
+ HEREDOC
45
+ "shadcn-phlexcomponents--hover-card-target": "trigger"
46
+ }
47
+ }
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class Input < Base
5
+ STYLES = <<~HEREDOC
6
+ flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1
7
+ text-base shadow-sm transition-colors file:border-0 file:bg-transparent
8
+ file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground
9
+ focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring
10
+ disabled:cursor-not-allowed disabled:opacity-50 md:text-sm
11
+ HEREDOC
12
+
13
+ def initialize(type: :text, name: nil, id: nil, **attributes)
14
+ @type = type
15
+ @name = name
16
+ @id = id || @name
17
+ super(**attributes)
18
+ end
19
+
20
+ def default_attributes
21
+ {
22
+ type: @type,
23
+ name: @name,
24
+ id: @id,
25
+ }
26
+ end
27
+
28
+ def view_template(&)
29
+ input(**@attributes, &)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+
5
+ class Label < Base
6
+ STYLES = <<~HEREDOC
7
+ text-sm font-medium leading-none peer-disabled:cursor-not-allowed
8
+ peer-disabled:opacity-70 block
9
+ HEREDOC
10
+
11
+ def view_template(&)
12
+ label(**@attributes, &)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class Link < Base
5
+ STYLES = "font-medium underline underline-offset-4"
6
+
7
+ def initialize(name = nil, options = nil, html_options = nil)
8
+ @name = name
9
+ @options = options
10
+ @html_options = html_options
11
+ end
12
+
13
+ def view_template(&)
14
+ @html_options, @options = @options, @name if block_given?
15
+ @html_options ||= {}
16
+ @html_options = mix(default_attributes, @html_options)
17
+ @html_options[:class] = TAILWIND_MERGER.merge("#{default_styles} #{@html_options[:class]}")
18
+
19
+ if block_given?
20
+ link_to(@options, @html_options, &)
21
+ else
22
+ link_to(@name, @options, @html_options)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class LoadingButton < Button
5
+ def default_attributes
6
+ {
7
+ type: @type,
8
+ data: {
9
+ controller: "shadcn-phlexcomponents--loading-button",
10
+ },
11
+ }
12
+ end
13
+
14
+ def view_template(&)
15
+ button(**@attributes) do
16
+ icon("loader-circle", class: "animate-spin hidden group-aria-busy:inline")
17
+ yield
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class Pagination < Base
5
+ STYLES = "mx-auto flex w-full justify-center"
6
+
7
+ def link(**attributes, &)
8
+ PaginationLink(**attributes, &)
9
+ end
10
+
11
+ def previous(**attributes, &)
12
+ PaginationPrevious(**attributes, &)
13
+ end
14
+
15
+ def next(**attributes, &)
16
+ PaginationNext(**attributes, &)
17
+ end
18
+
19
+ def ellipsis(**attributes, &)
20
+ PaginationEllipsis(**attributes, &)
21
+ end
22
+
23
+ def default_attributes
24
+ {
25
+ role: "navigation",
26
+ aria: {
27
+ label: "navigation",
28
+ }
29
+ }
30
+ end
31
+
32
+ def view_template(&)
33
+ div(**@attributes) do
34
+ ul(class: "flex flex-row items-center gap-1", &)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class PaginationEllipsis < Base
5
+ STYLES = "flex h-9 w-9 items-center justify-center"
6
+
7
+ def default_attributes
8
+ {
9
+ aria: {
10
+ hidden: "true"
11
+ }
12
+ }
13
+ end
14
+
15
+ def view_template
16
+ li do
17
+ span(**@attributes) do
18
+ icon("ellipsis", class: "size-4")
19
+ span(class: "sr-only") { "More pages" }
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class PaginationLink < Base
5
+ def initialize(href: nil, active: false, **attributes)
6
+ @href = href
7
+ @active = active
8
+ super(**attributes)
9
+ end
10
+
11
+ def default_styles
12
+ if @active
13
+ Button.default_styles(variant: :outline, size: :icon)
14
+ else
15
+ Button.default_styles(variant: :ghost, size: :icon)
16
+ end
17
+ end
18
+
19
+ def default_attributes
20
+ {
21
+ href: @href,
22
+ aria: {
23
+ current: @active ? "page" : nil
24
+ }
25
+ }
26
+ end
27
+
28
+ def view_template(&)
29
+ li do
30
+ a(**@attributes, &)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class PaginationNext < Base
5
+ def initialize(href: nil, **attributes)
6
+ @href = href
7
+ super(**attributes)
8
+ end
9
+
10
+ def default_styles
11
+ "#{Button.default_styles(variant: :ghost, size: :default)} gap-1 pr-2.5"
12
+ end
13
+
14
+ def default_attributes
15
+ {
16
+ href: @href,
17
+ aria: {
18
+ label: "Go to next page"
19
+ }
20
+ }
21
+ end
22
+
23
+ def view_template(&)
24
+ li do
25
+ a(**@attributes) do
26
+ span { "Next" }
27
+ icon("chevron-right", class: "size-4")
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class PaginationPrevious < Base
5
+ def initialize(href: nil, **attributes)
6
+ @href = href
7
+ super(**attributes)
8
+ end
9
+
10
+ def default_attributes
11
+ {
12
+ href: @href,
13
+ aria: {
14
+ label: "Go to previous page"
15
+ }
16
+ }
17
+ end
18
+
19
+ def default_styles
20
+ "#{Button.default_styles(variant: :ghost, size: :default)} gap-1 pl-2.5"
21
+ end
22
+
23
+ def view_template(&)
24
+ li do
25
+ a(**@attributes) do
26
+ icon("chevron-left", class: "size-4")
27
+ span { "Previous" }
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+
5
+ class Popover < Base
6
+ STYLES = "inline-block".freeze
7
+
8
+ def initialize(side: :bottom, aria_id: "popover-#{SecureRandom.hex(5)}", **attributes)
9
+ @side = side
10
+ @aria_id = aria_id
11
+ super(**attributes)
12
+ end
13
+
14
+ def content(**attributes, &)
15
+ PopoverContent(side: @side, aria_id: @aria_id, **attributes, &)
16
+ end
17
+
18
+ def trigger(**attributes, &)
19
+ PopoverTrigger(aria_id: @aria_id, **attributes, &)
20
+ end
21
+
22
+ def default_attributes
23
+ {
24
+ data: {
25
+ controller: "shadcn-phlexcomponents--popover",
26
+ side: @side
27
+ }
28
+ }
29
+ end
30
+
31
+ def view_template(&)
32
+ div(**@attributes, &)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class PopoverContent < Base
5
+ STYLES = <<~HEREDOC.freeze
6
+ z-50 rounded-md border w-72 bg-popover p-4 text-popover-foreground shadow-md outline-none
7
+ data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0
8
+ data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95
9
+ data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2
10
+ data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2
11
+ HEREDOC
12
+
13
+ def initialize(side: :bottom, aria_id: nil, **attributes)
14
+ @side = side
15
+ @aria_id = aria_id
16
+ super(**attributes)
17
+ end
18
+
19
+ def view_template(&)
20
+ div(class: 'hidden fixed top-0 left-0 w-max z-50', data: { "shadcn-phlexcomponents--popover-target": "contentWrapper" }) do
21
+ div(**@attributes, &)
22
+ end
23
+ end
24
+
25
+ def default_attributes
26
+ {
27
+ id: "#{@aria_id}-content",
28
+ tabindex: -1,
29
+ role: "dialog",
30
+ data: {
31
+ side: @side,
32
+ "shadcn-phlexcomponents--popover-target": "content"
33
+ }
34
+ }
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+
5
+ class PopoverTrigger < Base
6
+ def initialize(as_child: false, aria_id: nil, **attributes)
7
+ @as_child = as_child
8
+ @aria_id = aria_id
9
+ super(**attributes)
10
+ end
11
+
12
+ def view_template(&)
13
+ if @as_child
14
+ content = capture(&)
15
+ element = find_as_child(content.to_s)
16
+
17
+ vanish(&)
18
+ element_attributes = nokogiri_attributes_to_hash(element)
19
+ styles = TAILWIND_MERGER.merge("#{@attributes[:class]} #{element_attributes[:class]}")
20
+ merged_attributes = mix(@attributes, element_attributes)
21
+ merged_attributes[:class] = styles
22
+
23
+ if element.name == "button"
24
+ merged_attributes.delete(:role)
25
+ end
26
+
27
+ send(element.name, **merged_attributes) do
28
+ sanitize_as_child(element.children.to_s)
29
+ end
30
+ else
31
+ div(**@attributes, &)
32
+ end
33
+ end
34
+
35
+ def default_attributes
36
+ {
37
+ id: @id,
38
+ role: "button",
39
+ aria: {
40
+ haspopup: "dialog",
41
+ expanded: false,
42
+ controls: "#{@aria_id}-content"
43
+ },
44
+ data: {
45
+ as_child: @as_child.to_s,
46
+ action: "click->shadcn-phlexcomponents--popover#toggle",
47
+ "shadcn-phlexcomponents--popover-target": "trigger"
48
+ }
49
+ }
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class Progress < Base
5
+ STYLES = "relative h-2 w-full overflow-hidden rounded-full bg-primary/20"
6
+
7
+ def initialize(value: 0, **attributes)
8
+ @value = value
9
+ super(**attributes)
10
+ end
11
+
12
+ def default_attributes
13
+ {
14
+ role: "progressbar",
15
+ aria: {
16
+ valuemax: 100,
17
+ valuemin: 0,
18
+ valuenow: @value,
19
+ },
20
+ data: {
21
+ controller: "shadcn-phlexcomponents--progress",
22
+ "shadcn-phlexcomponents--progress-progress-value": @value
23
+ }
24
+ }
25
+ end
26
+
27
+ def view_template
28
+ div(**@attributes) do
29
+ div(
30
+ class: "h-full w-full flex-1 bg-primary transition-all",
31
+ style: "transform: translateX(-#{100-@value}%)",
32
+ data: { "shadcn-phlexcomponents--progress-target": "bar"}
33
+ )
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class RadioGroup < Base
5
+ STYLES = "grid gap-2 outline-none"
6
+
7
+ def initialize(name: nil, value: nil, dir: "ltr", include_hidden: true, **attributes)
8
+ @name = name
9
+ @value = value
10
+ @dir = dir
11
+ @include_hidden = include_hidden
12
+ super(**attributes)
13
+ end
14
+
15
+ def item(name: nil, value: nil, **attributes)
16
+ RadioGroupItem(name: name || @name, value: value, checked: @value == value, **attributes)
17
+ end
18
+
19
+ def items(collection, value_method:, text_method:, wrapper_class: nil)
20
+ wrapper_class = TAILWIND_MERGER.merge("flex items-center space-x-2 #{wrapper_class}")
21
+
22
+ if collection.first && collection.first.is_a?(Hash)
23
+ collection = convert_collection_hash_to_struct(collection, value_method: value_method, text_method: text_method)
24
+ end
25
+
26
+ collection.each do |item|
27
+ value = item.public_send(value_method)
28
+ text = item.public_send(text_method)
29
+ id = "#{@name.parameterize.underscore}_#{value}"
30
+
31
+ div(class: wrapper_class) do
32
+ RadioGroupItem(name: @name, value: value, checked: @value == value, id: id)
33
+ Label(for: id) { text }
34
+ end
35
+ end
36
+ end
37
+
38
+ def view_template(&)
39
+ div(**@attributes) do
40
+ if @include_hidden
41
+ input(type: "hidden", name: @name, autocomplete: "off")
42
+ end
43
+
44
+ yield
45
+ end
46
+ end
47
+
48
+ def default_attributes
49
+ {
50
+ role: "radiogroup",
51
+ dir: @dir,
52
+ aria: {
53
+ required: false,
54
+ },
55
+ data: {
56
+ controller: "shadcn-phlexcomponents--radio-group",
57
+ "shadcn-phlexcomponents--radio-group-selected-value": @value,
58
+ }
59
+ }
60
+ end
61
+ end
62
+ end