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.
- checksums.yaml +7 -0
- data/README.md +39 -0
- data/Rakefile +12 -0
- data/app/assets/tailwind/tailwindcss-animate.css +318 -0
- data/app/assets/tailwind/vanilla-calendar-pro.css +461 -0
- data/app/javascript/controllers/accordion_controller.js +133 -0
- data/app/javascript/controllers/alert_dialog_controller.js +157 -0
- data/app/javascript/controllers/avatar_controller.js +15 -0
- data/app/javascript/controllers/checkbox_controller.js +28 -0
- data/app/javascript/controllers/collapsible_controller.js +35 -0
- data/app/javascript/controllers/combobox_controller.js +291 -0
- data/app/javascript/controllers/datepicker_controller.js +47 -0
- data/app/javascript/controllers/dialog_controller.js +159 -0
- data/app/javascript/controllers/dropdown_menu_controller.js +193 -0
- data/app/javascript/controllers/hover_card_controller.js +135 -0
- data/app/javascript/controllers/loading_button_controller.js +15 -0
- data/app/javascript/controllers/popover_controller.js +124 -0
- data/app/javascript/controllers/progress_controller.js +14 -0
- data/app/javascript/controllers/radio_group_controller.js +90 -0
- data/app/javascript/controllers/select_controller.js +294 -0
- data/app/javascript/controllers/sheet_controller.js +159 -0
- data/app/javascript/controllers/sidebar_controller.js +36 -0
- data/app/javascript/controllers/sidebar_trigger_controller.js +15 -0
- data/app/javascript/controllers/switch_controller.js +24 -0
- data/app/javascript/controllers/tabs_controller.js +73 -0
- data/app/javascript/controllers/theme_switcher_controller.js +32 -0
- data/app/javascript/controllers/toast_container_controller.js +22 -0
- data/app/javascript/controllers/toast_controller.js +45 -0
- data/app/javascript/controllers/tooltip_controller.js +135 -0
- data/lib/components/accordion.rb +38 -0
- data/lib/components/accordion_content.rb +28 -0
- data/lib/components/accordion_item.rb +26 -0
- data/lib/components/accordion_trigger.rb +45 -0
- data/lib/components/alert.rb +40 -0
- data/lib/components/alert_description.rb +11 -0
- data/lib/components/alert_dialog.rb +60 -0
- data/lib/components/alert_dialog_action.rb +22 -0
- data/lib/components/alert_dialog_action_to.rb +37 -0
- data/lib/components/alert_dialog_cancel.rb +22 -0
- data/lib/components/alert_dialog_content.rb +40 -0
- data/lib/components/alert_dialog_description.rb +22 -0
- data/lib/components/alert_dialog_footer.rb +11 -0
- data/lib/components/alert_dialog_header.rb +11 -0
- data/lib/components/alert_dialog_title.rb +22 -0
- data/lib/components/alert_dialog_trigger.rb +50 -0
- data/lib/components/alert_title.rb +11 -0
- data/lib/components/aspect_ratio.rb +19 -0
- data/lib/components/avatar.rb +31 -0
- data/lib/components/avatar_fallback.rb +21 -0
- data/lib/components/avatar_image.rb +20 -0
- data/lib/components/badge.rb +36 -0
- data/lib/components/base.rb +108 -0
- data/lib/components/breadcrumb.rb +51 -0
- data/lib/components/breadcrumb_ellipsis.rb +23 -0
- data/lib/components/breadcrumb_item.rb +11 -0
- data/lib/components/breadcrumb_link.rb +7 -0
- data/lib/components/breadcrumb_page.rb +21 -0
- data/lib/components/breadcrumb_separator.rb +26 -0
- data/lib/components/button.rb +53 -0
- data/lib/components/card.rb +31 -0
- data/lib/components/card_content.rb +11 -0
- data/lib/components/card_description.rb +11 -0
- data/lib/components/card_footer.rb +11 -0
- data/lib/components/card_header.rb +11 -0
- data/lib/components/card_title.rb +11 -0
- data/lib/components/checkbox.rb +65 -0
- data/lib/components/checkbox_group.rb +48 -0
- data/lib/components/collapsible.rb +32 -0
- data/lib/components/collapsible_content.rb +25 -0
- data/lib/components/collapsible_trigger.rb +50 -0
- data/lib/components/datepicker.rb +38 -0
- data/lib/components/dialog.rb +52 -0
- data/lib/components/dialog_close.rb +42 -0
- data/lib/components/dialog_content.rb +54 -0
- data/lib/components/dialog_description.rb +22 -0
- data/lib/components/dialog_footer.rb +11 -0
- data/lib/components/dialog_header.rb +11 -0
- data/lib/components/dialog_title.rb +22 -0
- data/lib/components/dialog_trigger.rb +50 -0
- data/lib/components/dropdown_menu.rb +50 -0
- data/lib/components/dropdown_menu_content.rb +49 -0
- data/lib/components/dropdown_menu_item.rb +57 -0
- data/lib/components/dropdown_menu_item_to.rb +25 -0
- data/lib/components/dropdown_menu_label.rb +12 -0
- data/lib/components/dropdown_menu_separator.rb +20 -0
- data/lib/components/dropdown_menu_trigger.rb +58 -0
- data/lib/components/hover_card.rb +33 -0
- data/lib/components/hover_card_content.rb +36 -0
- data/lib/components/hover_card_trigger.rb +50 -0
- data/lib/components/input.rb +32 -0
- data/lib/components/label.rb +15 -0
- data/lib/components/link.rb +26 -0
- data/lib/components/loading_button.rb +21 -0
- data/lib/components/pagination.rb +38 -0
- data/lib/components/pagination_ellipsis.rb +24 -0
- data/lib/components/pagination_link.rb +34 -0
- data/lib/components/pagination_next.rb +32 -0
- data/lib/components/pagination_previous.rb +32 -0
- data/lib/components/popover.rb +35 -0
- data/lib/components/popover_content.rb +37 -0
- data/lib/components/popover_trigger.rb +52 -0
- data/lib/components/progress.rb +37 -0
- data/lib/components/radio_group.rb +62 -0
- data/lib/components/radio_group_item.rb +66 -0
- data/lib/components/select.rb +189 -0
- data/lib/components/select_content.rb +59 -0
- data/lib/components/select_group.rb +23 -0
- data/lib/components/select_item.rb +58 -0
- data/lib/components/select_label.rb +23 -0
- data/lib/components/select_trigger.rb +54 -0
- data/lib/components/separator.rb +29 -0
- data/lib/components/sheet.rb +53 -0
- data/lib/components/sheet_close.rb +42 -0
- data/lib/components/sheet_content.rb +67 -0
- data/lib/components/sheet_description.rb +22 -0
- data/lib/components/sheet_footer.rb +11 -0
- data/lib/components/sheet_header.rb +11 -0
- data/lib/components/sheet_title.rb +22 -0
- data/lib/components/sheet_trigger.rb +50 -0
- data/lib/components/sidebar.rb +103 -0
- data/lib/components/sidebar_container.rb +11 -0
- data/lib/components/sidebar_content.rb +11 -0
- data/lib/components/sidebar_footer.rb +11 -0
- data/lib/components/sidebar_group.rb +11 -0
- data/lib/components/sidebar_group_content.rb +11 -0
- data/lib/components/sidebar_group_label.rb +16 -0
- data/lib/components/sidebar_header.rb +11 -0
- data/lib/components/sidebar_inset.rb +15 -0
- data/lib/components/sidebar_menu.rb +11 -0
- data/lib/components/sidebar_menu_button.rb +61 -0
- data/lib/components/sidebar_menu_item.rb +9 -0
- data/lib/components/sidebar_menu_sub.rb +14 -0
- data/lib/components/sidebar_menu_sub_button.rb +48 -0
- data/lib/components/sidebar_menu_sub_item.rb +9 -0
- data/lib/components/sidebar_trigger.rb +40 -0
- data/lib/components/skeleton.rb +11 -0
- data/lib/components/switch.rb +65 -0
- data/lib/components/table.rb +73 -0
- data/lib/components/table_body.rb +11 -0
- data/lib/components/table_caption.rb +11 -0
- data/lib/components/table_cell.rb +11 -0
- data/lib/components/table_footer.rb +11 -0
- data/lib/components/table_head.rb +14 -0
- data/lib/components/table_header.rb +11 -0
- data/lib/components/table_row.rb +11 -0
- data/lib/components/tabs.rb +38 -0
- data/lib/components/tabs_content.rb +35 -0
- data/lib/components/tabs_list.rb +23 -0
- data/lib/components/tabs_trigger.rb +45 -0
- data/lib/components/textarea.rb +28 -0
- data/lib/components/theme_switcher.rb +21 -0
- data/lib/components/toast.rb +100 -0
- data/lib/components/toast_action.rb +38 -0
- data/lib/components/toast_action_to.rb +25 -0
- data/lib/components/toast_container.rb +44 -0
- data/lib/components/toast_content.rb +11 -0
- data/lib/components/toast_description.rb +11 -0
- data/lib/components/toast_title.rb +11 -0
- data/lib/components/tooltip.rb +34 -0
- data/lib/components/tooltip_content.rb +42 -0
- data/lib/components/tooltip_trigger.rb +50 -0
- data/lib/install/install_shadcn_phlexcomponents.rb +12 -0
- data/lib/shadcn_phlexcomponents/alias.rb +132 -0
- data/lib/shadcn_phlexcomponents/engine.rb +11 -0
- data/lib/shadcn_phlexcomponents/version.rb +5 -0
- data/lib/shadcn_phlexcomponents.rb +9 -0
- data/lib/tasks/install.rake +10 -0
- metadata +264 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class AlertDialogTrigger < 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 default_attributes
|
12
|
+
{
|
13
|
+
role: "button",
|
14
|
+
aria: {
|
15
|
+
haspopup: "dialog",
|
16
|
+
expanded: "false",
|
17
|
+
controls: "#{@aria_id}-content",
|
18
|
+
},
|
19
|
+
data: {
|
20
|
+
action: "click->shadcn-phlexcomponents--alert-dialog#open",
|
21
|
+
"shadcn-phlexcomponents--alert-dialog-target": "trigger",
|
22
|
+
as_child: @as_child.to_s
|
23
|
+
},
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def view_template(&)
|
28
|
+
if @as_child
|
29
|
+
content = capture(&)
|
30
|
+
element = find_as_child(content.to_s)
|
31
|
+
|
32
|
+
vanish(&)
|
33
|
+
element_attributes = nokogiri_attributes_to_hash(element)
|
34
|
+
styles = TAILWIND_MERGER.merge("#{@attributes[:class]} #{element_attributes[:class]}")
|
35
|
+
merged_attributes = mix(@attributes, element_attributes)
|
36
|
+
merged_attributes[:class] = styles
|
37
|
+
|
38
|
+
if element.name == "button"
|
39
|
+
merged_attributes.delete(:role)
|
40
|
+
end
|
41
|
+
|
42
|
+
send(element.name, **merged_attributes) do
|
43
|
+
sanitize_as_child(element.children.to_s)
|
44
|
+
end
|
45
|
+
else
|
46
|
+
div(**@attributes, &)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class AspectRatio < Base
|
5
|
+
STYLES = "absolute inset-0"
|
6
|
+
|
7
|
+
def initialize(ratio: "1/1", **attributes)
|
8
|
+
ratio_arr = ratio.split("/").map(&:to_f)
|
9
|
+
@ratio = ratio_arr[0] / ratio_arr[1]
|
10
|
+
super(**attributes)
|
11
|
+
end
|
12
|
+
|
13
|
+
def view_template(&)
|
14
|
+
div(style: { position: "relative", width: "100%", "padding-bottom": "#{100 / @ratio}%" }) do
|
15
|
+
div(**@attributes, &)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class Avatar < Base
|
5
|
+
STYLES = "relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full"
|
6
|
+
|
7
|
+
def initialize(**attributes)
|
8
|
+
super(**attributes)
|
9
|
+
end
|
10
|
+
|
11
|
+
def image(**attributes, &)
|
12
|
+
AvatarImage(**attributes, &)
|
13
|
+
end
|
14
|
+
|
15
|
+
def fallback(**attributes, &)
|
16
|
+
AvatarFallback(**attributes, &)
|
17
|
+
end
|
18
|
+
|
19
|
+
def default_attributes
|
20
|
+
{
|
21
|
+
data: {
|
22
|
+
controller: "shadcn-phlexcomponents--avatar",
|
23
|
+
},
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def view_template(&)
|
28
|
+
span(**@attributes, &)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class AvatarFallback < Base
|
5
|
+
STYLES = "flex h-full w-full items-center justify-center rounded-full bg-muted"
|
6
|
+
|
7
|
+
def default_attributes
|
8
|
+
{
|
9
|
+
data: {
|
10
|
+
"shadcn-phlexcomponents--avatar-target": "fallback",
|
11
|
+
},
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
def view_template(&)
|
16
|
+
@class = @attributes.delete(:class)
|
17
|
+
|
18
|
+
span(class: "#{@class} hidden", **@attributes, &)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
|
5
|
+
class AvatarImage < Base
|
6
|
+
STYLES = "aspect-square h-full w-full"
|
7
|
+
|
8
|
+
def default_attributes
|
9
|
+
{
|
10
|
+
data: {
|
11
|
+
"shadcn-phlexcomponents--avatar-target": "image",
|
12
|
+
},
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
def view_template(&)
|
17
|
+
img(**@attributes, &)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class Badge < Base
|
5
|
+
STYLES = <<~HEREDOC
|
6
|
+
inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold
|
7
|
+
transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2
|
8
|
+
HEREDOC
|
9
|
+
|
10
|
+
VARIANTS = {
|
11
|
+
primary: "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
|
12
|
+
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
13
|
+
destructive: "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
|
14
|
+
outline: "text-foreground",
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def default_styles(variant)
|
19
|
+
"#{STYLES} #{VARIANTS[variant]}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(variant: :primary, **attributes)
|
24
|
+
@variant = variant
|
25
|
+
super(**attributes)
|
26
|
+
end
|
27
|
+
|
28
|
+
def default_styles
|
29
|
+
self.class.default_styles(@variant)
|
30
|
+
end
|
31
|
+
|
32
|
+
def view_template(&)
|
33
|
+
div(**@attributes, &)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class Base < Phlex::HTML
|
5
|
+
# Include any helpers you want to be available across all components
|
6
|
+
include Phlex::Rails::Helpers::Sanitize
|
7
|
+
include Phlex::Rails::Helpers::LinkTo
|
8
|
+
include Phlex::Rails::Helpers::ButtonTo
|
9
|
+
|
10
|
+
TAILWIND_MERGER = ::TailwindMerge::Merger.new.freeze
|
11
|
+
STYLES = ""
|
12
|
+
|
13
|
+
SANITIZER_ALLOWED_TAGS = (Rails::HTML::SafeListSanitizer.allowed_tags.to_a +
|
14
|
+
[ "svg", "path", "polygon", "polyline", "circle", "ellipse", "rect", "line", "use", "defs", "g" ]).freeze
|
15
|
+
|
16
|
+
SANITIZER_ALLOWED_ATTRIBUTES = (Rails::HTML::SafeListSanitizer.allowed_attributes.to_a +
|
17
|
+
[
|
18
|
+
"viewBox",
|
19
|
+
"preserveaspectratio",
|
20
|
+
"cx",
|
21
|
+
"cy",
|
22
|
+
"d",
|
23
|
+
"fill",
|
24
|
+
"height",
|
25
|
+
"points",
|
26
|
+
"r",
|
27
|
+
"stroke",
|
28
|
+
"width",
|
29
|
+
"x",
|
30
|
+
"y",
|
31
|
+
"stroke-linejoin",
|
32
|
+
"stroke-width",
|
33
|
+
"stroke-linecap",
|
34
|
+
"aria-hidden",
|
35
|
+
"class"
|
36
|
+
]).freeze
|
37
|
+
|
38
|
+
def initialize(**attributes)
|
39
|
+
@attributes = mix(default_attributes, attributes)
|
40
|
+
@attributes[:class] = TAILWIND_MERGER.merge("#{default_styles} #{@attributes[:class]}")
|
41
|
+
end
|
42
|
+
|
43
|
+
if Rails.env.development?
|
44
|
+
def before_template
|
45
|
+
comment { "Before #{self.class.name}" }
|
46
|
+
super
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def default_attributes
|
51
|
+
{}
|
52
|
+
end
|
53
|
+
|
54
|
+
def default_styles
|
55
|
+
self.class::STYLES
|
56
|
+
end
|
57
|
+
|
58
|
+
def nokogiri_attributes_to_hash(element)
|
59
|
+
hash = {}
|
60
|
+
|
61
|
+
element.attributes.each do |key, attr|
|
62
|
+
hash[key] = attr.value
|
63
|
+
end
|
64
|
+
|
65
|
+
hash.transform_keys(&:to_sym)
|
66
|
+
end
|
67
|
+
|
68
|
+
def sanitize_as_child(html)
|
69
|
+
sanitize(
|
70
|
+
html,
|
71
|
+
tags: SANITIZER_ALLOWED_TAGS,
|
72
|
+
attributes: SANITIZER_ALLOWED_ATTRIBUTES,
|
73
|
+
)
|
74
|
+
end
|
75
|
+
|
76
|
+
def find_as_child(rendered_element)
|
77
|
+
fragment = Nokogiri::HTML.fragment(rendered_element)
|
78
|
+
element = fragment.children.find do |child|
|
79
|
+
if child.is_a?(Nokogiri::XML::Comment)
|
80
|
+
false
|
81
|
+
else
|
82
|
+
(child.is_a?(Nokogiri::XML::Text) && child.text.strip.present?) || !child.is_a?(Nokogiri::XML::Text)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
element
|
87
|
+
end
|
88
|
+
|
89
|
+
# https://github.com/heyvito/lucide-rails/blob/master/lib/lucide-rails/rails_helper.rb
|
90
|
+
def icon(named, **options)
|
91
|
+
options = options.with_indifferent_access
|
92
|
+
size = options.delete(:size)
|
93
|
+
options = options.merge width: size, height: size if size
|
94
|
+
|
95
|
+
svg(**LucideRails.default_options.merge(**options)) { LucideRails::IconProvider.icon(named).html_safe }
|
96
|
+
end
|
97
|
+
|
98
|
+
def convert_collection_hash_to_struct(collection, value_method:, text_method:)
|
99
|
+
structConstructor = Struct.new(value_method, text_method)
|
100
|
+
collection.map do |item|
|
101
|
+
struct = structConstructor.new
|
102
|
+
struct[value_method] = item[value_method]
|
103
|
+
struct[text_method] = item[text_method]
|
104
|
+
struct
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class Breadcrumb < Base
|
5
|
+
STYLES = "flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5"
|
6
|
+
|
7
|
+
def item(**attributes, &)
|
8
|
+
BreadcrumbItem(**attributes, &)
|
9
|
+
end
|
10
|
+
|
11
|
+
def link(name = nil, options = nil, html_options = nil, &block)
|
12
|
+
BreadcrumbLink(name, options, html_options, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def separator(**attributes, &)
|
16
|
+
BreadcrumbSeparator(**attributes, &)
|
17
|
+
end
|
18
|
+
|
19
|
+
def page(**attributes, &)
|
20
|
+
BreadcrumbPage(**attributes, &)
|
21
|
+
end
|
22
|
+
|
23
|
+
def ellipsis(**attributes)
|
24
|
+
BreadcrumbEllipsis(**attributes)
|
25
|
+
end
|
26
|
+
|
27
|
+
def links(collection)
|
28
|
+
collection.each_with_index do |link, index|
|
29
|
+
if index == collection.size - 1
|
30
|
+
item do
|
31
|
+
page { link[:name] }
|
32
|
+
end
|
33
|
+
else
|
34
|
+
item do
|
35
|
+
link(link[:name], link[:path])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
if index < collection.size - 1
|
40
|
+
separator
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def view_template(&)
|
46
|
+
nav(aria: { label: "breadcrumb" }) do
|
47
|
+
ol(**@attributes, &)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class BreadcrumbEllipsis < Base
|
5
|
+
STYLES = "flex h-9 w-9 items-center justify-center"
|
6
|
+
|
7
|
+
def default_attributes
|
8
|
+
{
|
9
|
+
role: "presentation",
|
10
|
+
aria: {
|
11
|
+
hidden: "true",
|
12
|
+
},
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
def view_template
|
17
|
+
span(**@attributes) do
|
18
|
+
icon("ellipsis", class: "size-4")
|
19
|
+
span(class: "sr-only") { "More" }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class BreadcrumbPage < Base
|
5
|
+
STYLES = "font-normal text-foreground"
|
6
|
+
|
7
|
+
def default_attributes
|
8
|
+
{
|
9
|
+
role: "link",
|
10
|
+
aria: {
|
11
|
+
disabled: "true",
|
12
|
+
current: "page",
|
13
|
+
},
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def view_template(&)
|
18
|
+
span(**@attributes, &)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class BreadcrumbSeparator < Base
|
5
|
+
STYLES = "[&>svg]:w-3.5 [&>svg]:h-3.5"
|
6
|
+
|
7
|
+
def default_attributes
|
8
|
+
{
|
9
|
+
role: "presentation",
|
10
|
+
aria: {
|
11
|
+
hidden: "true",
|
12
|
+
},
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
def view_template(&)
|
17
|
+
li(**@attributes) do
|
18
|
+
if block_given?
|
19
|
+
yield
|
20
|
+
else
|
21
|
+
icon("chevron-right")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class Button < Base
|
5
|
+
STYLES = <<~HEREDOC
|
6
|
+
inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md
|
7
|
+
text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1
|
8
|
+
focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50
|
9
|
+
[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 cursor-pointer
|
10
|
+
HEREDOC
|
11
|
+
|
12
|
+
VARIANTS = {
|
13
|
+
primary: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
14
|
+
secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
15
|
+
destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
16
|
+
outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
17
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
18
|
+
link: "text-primary underline-offset-4 hover:underline",
|
19
|
+
}.freeze
|
20
|
+
|
21
|
+
SIZES = {
|
22
|
+
default: "h-9 px-4 py-2",
|
23
|
+
sm: "h-8 rounded-md px-3 text-xs",
|
24
|
+
lg: "h-10 rounded-md px-8",
|
25
|
+
icon: "h-9 w-9",
|
26
|
+
}
|
27
|
+
|
28
|
+
class << self
|
29
|
+
def default_styles(variant:, size:)
|
30
|
+
"#{STYLES} #{VARIANTS[variant]} #{SIZES[size]}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(variant: :primary, size: :default, type: :button, **attributes)
|
35
|
+
@type = type
|
36
|
+
@variant = variant
|
37
|
+
@size = size
|
38
|
+
super(**attributes)
|
39
|
+
end
|
40
|
+
|
41
|
+
def default_attributes
|
42
|
+
{ type: @type }
|
43
|
+
end
|
44
|
+
|
45
|
+
def default_styles
|
46
|
+
self.class.default_styles(variant: @variant, size: @size)
|
47
|
+
end
|
48
|
+
|
49
|
+
def view_template(&)
|
50
|
+
button(**@attributes, &)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class Card < Base
|
5
|
+
STYLES = "rounded-xl border bg-card text-card-foreground shadow"
|
6
|
+
|
7
|
+
def header(**attributes, &)
|
8
|
+
CardHeader(**attributes, &)
|
9
|
+
end
|
10
|
+
|
11
|
+
def title(**attributes, &)
|
12
|
+
CardTitle(**attributes, &)
|
13
|
+
end
|
14
|
+
|
15
|
+
def description(**attributes, &)
|
16
|
+
CardDescription(**attributes, &)
|
17
|
+
end
|
18
|
+
|
19
|
+
def content(**attributes, &)
|
20
|
+
CardContent(**attributes, &)
|
21
|
+
end
|
22
|
+
|
23
|
+
def footer(**attributes, &)
|
24
|
+
CardFooter(**attributes, &)
|
25
|
+
end
|
26
|
+
|
27
|
+
def view_template(&)
|
28
|
+
div(**@attributes, &)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class Checkbox < Base
|
5
|
+
STYLES = <<~HEREDOC.freeze
|
6
|
+
peer size-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none
|
7
|
+
focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50
|
8
|
+
data-[checked=true]:bg-primary data-[checked=true]:text-primary-foreground relative
|
9
|
+
cursor-pointer group/checkbox
|
10
|
+
HEREDOC
|
11
|
+
|
12
|
+
def initialize(name: nil, value: "1", unchecked_value: "0", checked: false, id: nil, include_hidden: true, **attributes)
|
13
|
+
@name = name
|
14
|
+
@value = value
|
15
|
+
@unchecked_value = unchecked_value
|
16
|
+
@checked = checked
|
17
|
+
@id = id || name
|
18
|
+
@include_hidden = include_hidden
|
19
|
+
super(**attributes)
|
20
|
+
end
|
21
|
+
|
22
|
+
def view_template(&)
|
23
|
+
button(**@attributes) do
|
24
|
+
span(class: "absolute inset-0 items-center justify-center text-current
|
25
|
+
pointer-events-none hidden group-data-[checked=true]/checkbox:flex") do
|
26
|
+
icon("check", class: "size-4")
|
27
|
+
end
|
28
|
+
|
29
|
+
if @include_hidden
|
30
|
+
input(name: @name, type: "hidden", value: @unchecked_value, autocomplete: "off")
|
31
|
+
end
|
32
|
+
|
33
|
+
input(
|
34
|
+
type: "checkbox",
|
35
|
+
value: @value,
|
36
|
+
class: "-translate-x-full pointer-events-none absolute top-0 left-0 size-4 opacity-0",
|
37
|
+
name: @name,
|
38
|
+
tabindex: -1,
|
39
|
+
checked: @checked,
|
40
|
+
aria: { hidden: true },
|
41
|
+
data: {
|
42
|
+
"shadcn-phlexcomponents--checkbox-target": "input"
|
43
|
+
}
|
44
|
+
)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def default_attributes
|
49
|
+
{
|
50
|
+
id: @id,
|
51
|
+
type: "button",
|
52
|
+
role: "checkbox",
|
53
|
+
aria: {
|
54
|
+
checked: @checked.to_s,
|
55
|
+
},
|
56
|
+
data: {
|
57
|
+
checked: @checked.to_s,
|
58
|
+
controller: "shadcn-phlexcomponents--checkbox",
|
59
|
+
action: "click->shadcn-phlexcomponents--checkbox#toggle keydown.enter->shadcn-phlexcomponents--checkbox#preventDefault",
|
60
|
+
"shadcn-phlexcomponents--checkbox-checked-value": @checked,
|
61
|
+
}
|
62
|
+
}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|