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,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class CheckboxGroup < Base
|
5
|
+
STYLES = "space-y-1.5"
|
6
|
+
|
7
|
+
def initialize(name:, value: [], include_hidden: true, **attributes)
|
8
|
+
@name = name
|
9
|
+
@value = value
|
10
|
+
@include_hidden = include_hidden
|
11
|
+
super(**attributes)
|
12
|
+
end
|
13
|
+
|
14
|
+
def items(collection, value_method:, text_method:, wrapper_class: nil)
|
15
|
+
wrapper_class = TAILWIND_MERGER.merge("flex items-center space-x-2 #{wrapper_class}")
|
16
|
+
|
17
|
+
if collection.first && collection.first.is_a?(Hash)
|
18
|
+
collection = convert_collection_hash_to_struct(collection, value_method: value_method, text_method: text_method)
|
19
|
+
end
|
20
|
+
|
21
|
+
collection.each do |item|
|
22
|
+
value = item.public_send(value_method)
|
23
|
+
text = item.public_send(text_method)
|
24
|
+
id = "#{@name.parameterize.underscore}_#{value}"
|
25
|
+
|
26
|
+
div(class: wrapper_class) do
|
27
|
+
Checkbox(name: "#{@name}[]",
|
28
|
+
id: id,
|
29
|
+
value: value,
|
30
|
+
checked: @value.include?(value),
|
31
|
+
include_hidden: false
|
32
|
+
)
|
33
|
+
Label(for: id) { text }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def view_template(&)
|
39
|
+
div(**@attributes) do
|
40
|
+
yield
|
41
|
+
|
42
|
+
if @include_hidden
|
43
|
+
input(type: "hidden", name: "#{@name}[]", autocomplete: "off")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class Collapsible < Base
|
5
|
+
|
6
|
+
def initialize(open: false, aria_id: "collapsible-#{SecureRandom.hex(5)}", **attributes)
|
7
|
+
@open = open
|
8
|
+
@aria_id = aria_id
|
9
|
+
super(**attributes)
|
10
|
+
end
|
11
|
+
|
12
|
+
def trigger(**attributes, &)
|
13
|
+
CollapsibleTrigger(open: @open, aria_id: @aria_id, **attributes, &)
|
14
|
+
end
|
15
|
+
|
16
|
+
def content(**attributes, &)
|
17
|
+
CollapsibleContent(aria_id: @aria_id, **attributes, &)
|
18
|
+
end
|
19
|
+
|
20
|
+
def default_attributes
|
21
|
+
{
|
22
|
+
data: {
|
23
|
+
controller: "shadcn-phlexcomponents--collapsible"
|
24
|
+
}
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
def view_template(&)
|
29
|
+
div(**@attributes, &)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class CollapsibleContent < Base
|
5
|
+
|
6
|
+
def initialize(aria_id: :nil, **attributes)
|
7
|
+
@aria_id = aria_id
|
8
|
+
super(**attributes)
|
9
|
+
end
|
10
|
+
|
11
|
+
def default_attributes
|
12
|
+
{
|
13
|
+
id: "#{@aria_id}-content",
|
14
|
+
data: {
|
15
|
+
"shadcn-phlexcomponents--collapsible-target": "content"
|
16
|
+
}
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def view_template(&)
|
21
|
+
@class = @attributes.delete(:class)
|
22
|
+
div(class: "#{@class} hidden", **@attributes, &)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class CollapsibleTrigger < Base
|
5
|
+
def initialize(open: false, as_child: false, aria_id: nil, **attributes)
|
6
|
+
@open = open
|
7
|
+
@as_child = as_child
|
8
|
+
@aria_id = aria_id
|
9
|
+
super(**attributes)
|
10
|
+
end
|
11
|
+
|
12
|
+
def default_attributes
|
13
|
+
{
|
14
|
+
role: "button",
|
15
|
+
aria: {
|
16
|
+
expanded: @open.to_s,
|
17
|
+
controls: "#{@aria_id}-content"
|
18
|
+
},
|
19
|
+
data: {
|
20
|
+
state: @open ? "open" : 'closed',
|
21
|
+
action: "click->shadcn-phlexcomponents--collapsible#toggle",
|
22
|
+
"shadcn-phlexcomponents--collapsible-target": "trigger"
|
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,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class Datepicker < 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
|
+
file:pt-0.5
|
12
|
+
HEREDOC
|
13
|
+
|
14
|
+
def initialize(name: nil, id: nil, value: nil, format: nil, settings: {}, **attributes)
|
15
|
+
@name = name
|
16
|
+
@id = id || @name
|
17
|
+
@value = value
|
18
|
+
@settings = settings
|
19
|
+
@format = format
|
20
|
+
super(**attributes)
|
21
|
+
end
|
22
|
+
|
23
|
+
def default_attributes
|
24
|
+
{
|
25
|
+
data: {
|
26
|
+
value: @value&.utc.to_s,
|
27
|
+
format: @format,
|
28
|
+
controller: "shadcn-phlexcomponents--datepicker",
|
29
|
+
settings: @settings.to_json
|
30
|
+
}
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
def view_template
|
35
|
+
input(type: :text, readonly: true, **@attributes)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class Dialog < Base
|
5
|
+
STYLES = "inline-block"
|
6
|
+
|
7
|
+
def initialize(aria_id: "dialog-#{SecureRandom.hex(5)}", **attributes)
|
8
|
+
@aria_id = aria_id
|
9
|
+
super(**attributes)
|
10
|
+
end
|
11
|
+
|
12
|
+
def trigger(**attributes, &)
|
13
|
+
render(DialogTrigger.new(aria_id: @aria_id, **attributes, &))
|
14
|
+
end
|
15
|
+
|
16
|
+
def content(**attributes, &)
|
17
|
+
render(DialogContent.new(aria_id: @aria_id, **attributes, &))
|
18
|
+
end
|
19
|
+
|
20
|
+
def header(**attributes, &)
|
21
|
+
render(DialogHeader.new(**attributes, &))
|
22
|
+
end
|
23
|
+
|
24
|
+
def title(**attributes, &)
|
25
|
+
render(DialogTitle.new(aria_id: @aria_id, **attributes, &))
|
26
|
+
end
|
27
|
+
|
28
|
+
def description(**attributes, &)
|
29
|
+
render(DialogDescription.new(aria_id: @aria_id, **attributes, &))
|
30
|
+
end
|
31
|
+
|
32
|
+
def footer(**attributes, &)
|
33
|
+
render(DialogFooter.new(**attributes, &))
|
34
|
+
end
|
35
|
+
|
36
|
+
def close(**attributes, &)
|
37
|
+
render(DialogClose.new(**attributes, &))
|
38
|
+
end
|
39
|
+
|
40
|
+
def default_attributes
|
41
|
+
{
|
42
|
+
data: {
|
43
|
+
controller: "shadcn-phlexcomponents--dialog",
|
44
|
+
},
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def view_template(&)
|
49
|
+
div(**@attributes, &)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class DialogClose < Base
|
5
|
+
def initialize(as_child: false, **attributes)
|
6
|
+
@as_child = as_child
|
7
|
+
super(**attributes)
|
8
|
+
end
|
9
|
+
|
10
|
+
def default_attributes
|
11
|
+
{
|
12
|
+
role: "button",
|
13
|
+
data: {
|
14
|
+
action: "click->shadcn-phlexcomponents--dialog#close",
|
15
|
+
},
|
16
|
+
}
|
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
|
+
element_attributes = nokogiri_attributes_to_hash(element)
|
26
|
+
styles = TAILWIND_MERGER.merge("#{@attributes[:class]} #{element_attributes[:class]}")
|
27
|
+
merged_attributes = mix(@attributes, element_attributes)
|
28
|
+
merged_attributes[:class] = styles
|
29
|
+
|
30
|
+
if element.name == "button"
|
31
|
+
merged_attributes.delete(:role)
|
32
|
+
end
|
33
|
+
|
34
|
+
send(element.name, **merged_attributes) do
|
35
|
+
sanitize_as_child(element.children.to_s)
|
36
|
+
end
|
37
|
+
else
|
38
|
+
div(**@attributes, &)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class DialogContent < Base
|
5
|
+
STYLES = <<~HEREDOC
|
6
|
+
fixed left-[50%] top-[50%] z-51 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
|
+
CLOSE_BUTTON_STYLES = <<~HEREDOC
|
15
|
+
absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background
|
16
|
+
transition-opacity hover:opacity-100 focus:outline-none focus:ring-2
|
17
|
+
focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none
|
18
|
+
cursor-pointer
|
19
|
+
HEREDOC
|
20
|
+
|
21
|
+
def initialize(aria_id: nil, **attributes)
|
22
|
+
@aria_id = aria_id
|
23
|
+
super(**attributes)
|
24
|
+
end
|
25
|
+
|
26
|
+
def default_attributes
|
27
|
+
{
|
28
|
+
id: "#{@aria_id}-content",
|
29
|
+
tabindex: -1,
|
30
|
+
role: "dialog",
|
31
|
+
aria: {
|
32
|
+
describedby: "#{@aria_id}-description",
|
33
|
+
labelledby: "#{@aria_id}-title",
|
34
|
+
},
|
35
|
+
data: {
|
36
|
+
"shadcn-phlexcomponents--dialog-target": "content",
|
37
|
+
state: "closed"
|
38
|
+
},
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def view_template(&)
|
43
|
+
@class = @attributes.delete(:class)
|
44
|
+
div(class: "#{@class} hidden", **@attributes) do
|
45
|
+
yield
|
46
|
+
|
47
|
+
button(class: CLOSE_BUTTON_STYLES, data: { action: "click->shadcn-phlexcomponents--dialog#close" }) do
|
48
|
+
icon("x", class: "size-4")
|
49
|
+
span(class: "sr-only") { "close" }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class DialogDescription < Base
|
5
|
+
STYLES = "text-sm text-muted-foreground"
|
6
|
+
|
7
|
+
def initialize(aria_id: nil, **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,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class DialogTitle < Base
|
5
|
+
STYLES = "text-lg font-semibold leading-none tracking-tight"
|
6
|
+
|
7
|
+
def initialize(aria_id: nil, **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
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class DialogTrigger < 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--dialog#open",
|
21
|
+
"shadcn-phlexcomponents--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,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class DropdownMenu < Base
|
5
|
+
STYLES = "inline-block".freeze
|
6
|
+
|
7
|
+
def initialize(side: :bottom, aria_id: "dropdown-menu-#{SecureRandom.hex(5)}", **attributes)
|
8
|
+
@side = side
|
9
|
+
@aria_id = aria_id
|
10
|
+
super(**attributes)
|
11
|
+
end
|
12
|
+
|
13
|
+
def trigger(**attributes, &)
|
14
|
+
DropdownMenuTrigger(aria_id: @aria_id, **attributes, &)
|
15
|
+
end
|
16
|
+
|
17
|
+
def content(**attributes, &)
|
18
|
+
DropdownMenuContent(aria_id: @aria_id, side: @side, **attributes, &)
|
19
|
+
end
|
20
|
+
|
21
|
+
def label(**attributes, &)
|
22
|
+
DropdownMenuLabel(**attributes, &)
|
23
|
+
end
|
24
|
+
|
25
|
+
def item(**attributes, &)
|
26
|
+
DropdownMenuItem(**attributes, &)
|
27
|
+
end
|
28
|
+
|
29
|
+
def item_to(name = nil, options = nil, html_options = nil, &block)
|
30
|
+
DropdownMenuItemTo(name, options, html_options, &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def separator(**attributes, &)
|
34
|
+
DropdownMenuSeparator(**attributes, &)
|
35
|
+
end
|
36
|
+
|
37
|
+
def default_attributes
|
38
|
+
{
|
39
|
+
data: {
|
40
|
+
controller: "shadcn-phlexcomponents--dropdown-menu",
|
41
|
+
side: @side
|
42
|
+
}
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
def view_template(&)
|
47
|
+
div(**@attributes, &)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class DropdownMenuContent < Base
|
5
|
+
STYLES = <<~HEREDOC.freeze
|
6
|
+
z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1
|
7
|
+
text-popover-foreground shadow-md outline-none
|
8
|
+
data-[state=open]:animate-in
|
9
|
+
data-[state=closed]:animate-out data-[state=closed]:fade-out-0
|
10
|
+
data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95
|
11
|
+
data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2
|
12
|
+
data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2
|
13
|
+
data-[side=top]:slide-in-from-bottom-2
|
14
|
+
HEREDOC
|
15
|
+
|
16
|
+
def initialize(side: :bottom, aria_id: nil, **attributes)
|
17
|
+
@side = side
|
18
|
+
@aria_id = aria_id
|
19
|
+
super(**attributes)
|
20
|
+
end
|
21
|
+
|
22
|
+
def view_template(&)
|
23
|
+
div(class: "hidden fixed top-0 left-0 w-max z-50", data: { "shadcn-phlexcomponents--dropdown-menu-target": "contentWrapper" }) do
|
24
|
+
div(**@attributes, &)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def default_attributes
|
29
|
+
{
|
30
|
+
id: "#{@aria_id}-content",
|
31
|
+
tabindex: -1,
|
32
|
+
role: "menu",
|
33
|
+
aria: {
|
34
|
+
labelledby: "#{@aria_id}-trigger",
|
35
|
+
orientation: "vertical"
|
36
|
+
},
|
37
|
+
data: {
|
38
|
+
state: "closed",
|
39
|
+
side: @side,
|
40
|
+
"shadcn-phlexcomponents--dropdown-menu-target": "content",
|
41
|
+
action: <<~HEREDOC,
|
42
|
+
keydown.up->shadcn-phlexcomponents--dropdown-menu#focusLastItem:prevent
|
43
|
+
keydown.down->shadcn-phlexcomponents--dropdown-menu#focusFirstItem:prevent
|
44
|
+
HEREDOC
|
45
|
+
}
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
|
5
|
+
class DropdownMenuItem < Base
|
6
|
+
STYLES = <<~HEREDOC.freeze
|
7
|
+
relative flex cursor-default select-none items-center gap-2 rounded-sm px-2
|
8
|
+
py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground
|
9
|
+
data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0
|
10
|
+
HEREDOC
|
11
|
+
|
12
|
+
def initialize(as_child: false, disabled: false, **attributes)
|
13
|
+
@as_child = as_child
|
14
|
+
@disabled = disabled
|
15
|
+
super(**attributes)
|
16
|
+
end
|
17
|
+
|
18
|
+
def view_template(&)
|
19
|
+
if @as_child
|
20
|
+
content = capture(&)
|
21
|
+
element = find_as_child(content.to_s)
|
22
|
+
|
23
|
+
vanish(&)
|
24
|
+
element_attributes = nokogiri_attributes_to_hash(element)
|
25
|
+
styles = TAILWIND_MERGER.merge("#{@attributes[:class]} #{element_attributes[:class]}")
|
26
|
+
merged_attributes = mix(@attributes, element_attributes)
|
27
|
+
merged_attributes[:class] = styles
|
28
|
+
|
29
|
+
send(element.name, **merged_attributes) do
|
30
|
+
sanitize_as_child(element.children.to_s)
|
31
|
+
end
|
32
|
+
else
|
33
|
+
div(**@attributes, &)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def default_attributes
|
38
|
+
{
|
39
|
+
role: "menuitem",
|
40
|
+
tabindex: -1,
|
41
|
+
data: {
|
42
|
+
disabled: @disabled,
|
43
|
+
action: <<~HEREDOC,
|
44
|
+
click->shadcn-phlexcomponents--dropdown-menu#selectItem
|
45
|
+
keydown.up->shadcn-phlexcomponents--dropdown-menu#focusPrevItem:stop
|
46
|
+
keydown.down->shadcn-phlexcomponents--dropdown-menu#focusNextItem:stop
|
47
|
+
keydown.enter->shadcn-phlexcomponents--dropdown-menu#selectItem:prevent
|
48
|
+
keydown.space->shadcn-phlexcomponents--dropdown-menu#selectItem:prevent
|
49
|
+
mouseover->shadcn-phlexcomponents--dropdown-menu#focusItem
|
50
|
+
mouseout->shadcn-phlexcomponents--dropdown-menu#focusContent
|
51
|
+
HEREDOC
|
52
|
+
"shadcn-phlexcomponents--dropdown-menu-target": "item"
|
53
|
+
}
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShadcnPhlexcomponents
|
4
|
+
class DropdownMenuItemTo < DropdownMenuItem
|
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
|
+
@disabled = @html_options[:disabled]
|
15
|
+
@html_options = mix(default_attributes, @html_options)
|
16
|
+
@html_options[:class] = TAILWIND_MERGER.merge("w-full #{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,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ShadcnPhlexcomponents
|
3
|
+
|
4
|
+
class DropdownMenuSeparator < Base
|
5
|
+
STYLES = "-mx-1 my-1 h-px bg-muted".freeze
|
6
|
+
|
7
|
+
def view_template(&)
|
8
|
+
div(**@attributes, &)
|
9
|
+
end
|
10
|
+
|
11
|
+
def default_attributes
|
12
|
+
{
|
13
|
+
role: "separator",
|
14
|
+
aria: {
|
15
|
+
orientation: "horizontal"
|
16
|
+
}
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|