shadcn-rails 0.1.0 → 0.2.1
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 +4 -4
- data/CHANGELOG.md +69 -2
- data/README.md +102 -1398
- data/__mocks__/@floating-ui/dom.js +67 -0
- data/app/assets/javascripts/shadcn/controllers/base_menu_controller.js +266 -0
- data/app/assets/javascripts/shadcn/controllers/combobox_controller.js +34 -8
- data/app/assets/javascripts/shadcn/controllers/command_controller.js +5 -1
- data/app/assets/javascripts/shadcn/controllers/context_menu_controller.js +64 -135
- data/app/assets/javascripts/shadcn/controllers/dropdown_controller.js +56 -186
- data/app/assets/javascripts/shadcn/controllers/hover_card_controller.js +29 -55
- data/app/assets/javascripts/shadcn/controllers/menubar_controller.js +10 -7
- data/app/assets/javascripts/shadcn/controllers/navigation_menu_controller.js +10 -6
- data/app/assets/javascripts/shadcn/controllers/popover_controller.js +35 -60
- data/app/assets/javascripts/shadcn/controllers/select_controller.js +37 -17
- data/app/assets/javascripts/shadcn/controllers/sidebar_controller.js +24 -14
- data/app/assets/javascripts/shadcn/controllers/tooltip_controller.js +28 -59
- data/app/assets/javascripts/shadcn/index.js +9 -1
- data/app/assets/javascripts/shadcn/utils/floating.js +179 -0
- data/app/assets/stylesheets/shadcn/base.css +32 -0
- data/app/assets/stylesheets/shadcn/components.css +12 -0
- data/app/components/shadcn/accordion_component.html.erb +8 -0
- data/app/components/shadcn/accordion_component.rb +6 -15
- data/app/components/shadcn/alert_component.html.erb +6 -0
- data/app/components/shadcn/alert_component.rb +0 -18
- data/app/components/shadcn/alert_dialog_component.html.erb +12 -0
- data/app/components/shadcn/alert_dialog_component.rb +7 -27
- data/app/components/shadcn/aspect_ratio_component.html.erb +7 -0
- data/app/components/shadcn/aspect_ratio_component.rb +4 -19
- data/app/components/shadcn/avatar_component.html.erb +20 -0
- data/app/components/shadcn/avatar_component.rb +8 -36
- data/app/components/shadcn/badge_component.html.erb +1 -0
- data/app/components/shadcn/badge_component.rb +0 -11
- data/app/components/shadcn/base_component.rb +15 -2
- data/app/components/shadcn/breadcrumb_component.html.erb +5 -0
- data/app/components/shadcn/breadcrumb_component.rb +6 -16
- data/app/components/shadcn/button_component.html.erb +18 -0
- data/app/components/shadcn/button_component.rb +1 -41
- data/app/components/shadcn/card_component.html.erb +8 -0
- data/app/components/shadcn/card_component.rb +2 -6
- data/app/components/shadcn/checkbox_component.html.erb +32 -0
- data/app/components/shadcn/checkbox_component.rb +4 -43
- data/app/components/shadcn/collapsible_component.html.erb +8 -0
- data/app/components/shadcn/collapsible_component.rb +6 -15
- data/app/components/shadcn/command_list_component.rb +29 -14
- data/app/components/shadcn/context_menu_checkbox_item_component.rb +76 -0
- data/app/components/shadcn/context_menu_component.html.erb +11 -0
- data/app/components/shadcn/context_menu_component.rb +6 -26
- data/app/components/shadcn/context_menu_content_component.rb +37 -14
- data/app/components/shadcn/context_menu_item_component.rb +3 -2
- data/app/components/shadcn/context_menu_radio_group_component.rb +42 -0
- data/app/components/shadcn/context_menu_radio_item_component.rb +76 -0
- data/app/components/shadcn/dialog_component.html.erb +14 -0
- data/app/components/shadcn/dialog_component.rb +8 -29
- data/app/components/shadcn/drawer_component.html.erb +12 -0
- data/app/components/shadcn/drawer_component.rb +7 -27
- data/app/components/shadcn/dropdown_menu_checkbox_item_component.rb +76 -0
- data/app/components/shadcn/dropdown_menu_component.html.erb +14 -0
- data/app/components/shadcn/dropdown_menu_component.rb +9 -29
- data/app/components/shadcn/dropdown_menu_content_component.rb +45 -16
- data/app/components/shadcn/dropdown_menu_radio_group_component.rb +42 -0
- data/app/components/shadcn/dropdown_menu_radio_item_component.rb +76 -0
- data/app/components/shadcn/field_component.rb +7 -8
- data/app/components/shadcn/hover_card_component.html.erb +12 -0
- data/app/components/shadcn/hover_card_component.rb +7 -26
- data/app/components/shadcn/input_component.html.erb +18 -0
- data/app/components/shadcn/input_component.rb +2 -27
- data/app/components/shadcn/input_otp_component.rb +3 -3
- data/app/components/shadcn/kbd_component.html.erb +1 -0
- data/app/components/shadcn/kbd_component.rb +3 -10
- data/app/components/shadcn/label_component.html.erb +3 -0
- data/app/components/shadcn/label_component.rb +2 -18
- data/app/components/shadcn/menubar_component.html.erb +6 -0
- data/app/components/shadcn/menubar_component.rb +4 -15
- data/app/components/shadcn/menubar_content_component.rb +45 -20
- data/app/components/shadcn/menubar_sub_content_component.rb +21 -8
- data/app/components/shadcn/native_select_component.html.erb +22 -0
- data/app/components/shadcn/native_select_component.rb +9 -39
- data/app/components/shadcn/navigation_menu_component.html.erb +6 -0
- data/app/components/shadcn/navigation_menu_component.rb +4 -15
- data/app/components/shadcn/pagination_component.html.erb +5 -0
- data/app/components/shadcn/pagination_component.rb +11 -15
- data/app/components/shadcn/popover_component.html.erb +15 -0
- data/app/components/shadcn/popover_component.rb +10 -30
- data/app/components/shadcn/progress_component.html.erb +13 -0
- data/app/components/shadcn/progress_component.rb +6 -26
- data/app/components/shadcn/radio_group_component.html.erb +8 -0
- data/app/components/shadcn/radio_group_component.rb +12 -26
- data/app/components/shadcn/radio_group_item_component.rb +32 -6
- data/app/components/shadcn/resizable_panel_group_component.rb +27 -16
- data/app/components/shadcn/scroll_area_component.html.erb +7 -0
- data/app/components/shadcn/scroll_area_component.rb +4 -16
- data/app/components/shadcn/select_component.html.erb +46 -0
- data/app/components/shadcn/select_component.rb +29 -86
- data/app/components/shadcn/separator_component.html.erb +5 -0
- data/app/components/shadcn/separator_component.rb +6 -14
- data/app/components/shadcn/sheet_component.html.erb +12 -0
- data/app/components/shadcn/sheet_component.rb +7 -27
- data/app/components/shadcn/sidebar_component.rb +2 -2
- data/app/components/shadcn/skeleton_component.html.erb +1 -0
- data/app/components/shadcn/skeleton_component.rb +4 -2
- data/app/components/shadcn/slider_component.html.erb +12 -0
- data/app/components/shadcn/slider_component.rb +2 -21
- data/app/components/shadcn/spinner_component.html.erb +18 -0
- data/app/components/shadcn/spinner_component.rb +2 -30
- data/app/components/shadcn/switch_component.html.erb +72 -0
- data/app/components/shadcn/switch_component.rb +4 -82
- data/app/components/shadcn/table_component.html.erb +9 -0
- data/app/components/shadcn/table_component.rb +2 -10
- data/app/components/shadcn/tabs_component.html.erb +8 -0
- data/app/components/shadcn/tabs_component.rb +4 -17
- data/app/components/shadcn/textarea_component.html.erb +13 -0
- data/app/components/shadcn/textarea_component.rb +6 -22
- data/app/components/shadcn/toast_component.html.erb +36 -0
- data/app/components/shadcn/toast_component.rb +6 -54
- data/app/components/shadcn/toggle_component.html.erb +12 -0
- data/app/components/shadcn/toggle_component.rb +6 -21
- data/app/components/shadcn/toggle_group_component.html.erb +14 -0
- data/app/components/shadcn/toggle_group_component.rb +6 -29
- data/app/components/shadcn/tooltip_component.html.erb +20 -0
- data/app/components/shadcn/tooltip_component.rb +13 -38
- data/lib/generators/shadcn/add/USAGE +24 -0
- data/lib/generators/shadcn/add/add_generator.rb +279 -0
- data/lib/generators/shadcn/install/USAGE +22 -0
- data/lib/generators/shadcn/install/install_generator.rb +8 -3
- data/lib/generators/shadcn/install/templates/initializer.rb.tt +7 -27
- data/lib/generators/shadcn/install/templates/shadcn.yml.tt +15 -31
- data/lib/shadcn/rails/version.rb +1 -1
- metadata +54 -42
- data/.dockerignore +0 -40
- data/CLAUDE.md +0 -463
- data/PROGRESS.md +0 -485
- data/Rakefile +0 -29
- data/__tests__/controllers/__snapshots__/calendar_controller.test.js.snap +0 -13
- data/__tests__/controllers/__snapshots__/popover_controller.test.js.snap +0 -46
- data/__tests__/controllers/__snapshots__/sheet_controller.test.js.snap +0 -111
- data/__tests__/controllers/__snapshots__/tabs_controller.test.js.snap +0 -27
- data/__tests__/controllers/accordion_controller.test.js +0 -904
- data/__tests__/controllers/calendar_controller.test.js +0 -1370
- data/__tests__/controllers/carousel_controller.test.js +0 -912
- data/__tests__/controllers/checkbox_controller.test.js +0 -454
- data/__tests__/controllers/collapsible_controller.test.js +0 -407
- data/__tests__/controllers/combobox_controller.test.js +0 -966
- data/__tests__/controllers/context_menu_controller.test.js +0 -627
- data/__tests__/controllers/date_picker_controller.test.js +0 -636
- data/__tests__/controllers/dialog_controller.test.js +0 -878
- data/__tests__/controllers/drawer_controller.test.js +0 -995
- data/__tests__/controllers/menubar_controller.test.js +0 -736
- data/__tests__/controllers/navigation_menu_controller.test.js +0 -598
- data/__tests__/controllers/popover_controller.test.js +0 -1007
- data/__tests__/controllers/radio_group_controller.test.js +0 -640
- data/__tests__/controllers/resizable_controller.test.js +0 -680
- data/__tests__/controllers/select_controller.test.js +0 -674
- data/__tests__/controllers/sheet_controller.test.js +0 -986
- data/__tests__/controllers/slider_controller.test.js +0 -1036
- data/__tests__/controllers/switch_controller.test.js +0 -424
- data/__tests__/controllers/tabs_controller.test.js +0 -907
- data/__tests__/controllers/toggle_group_controller.test.js +0 -839
- data/__tests__/controllers/tooltip_controller.test.js +0 -808
- data/__tests__/helpers/stimulus-test-helper.js +0 -203
- data/babel.config.cjs +0 -5
- data/bin/console +0 -11
- data/bin/setup +0 -8
- data/jest.config.js +0 -19
- data/jest.setup.js +0 -8
- data/lib/generators/shadcn/component/component_generator.rb +0 -188
- data/lib/generators/shadcn/theme/theme_generator.rb +0 -128
- data/package-lock.json +0 -7415
- data/package.json +0 -68
- data/rollup.config.js +0 -29
|
@@ -28,37 +28,17 @@ module Shadcn
|
|
|
28
28
|
ContextMenuContentComponent.new(**options)
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
def call
|
|
32
|
-
content_tag(:div, context_menu_content, context_menu_attributes)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
31
|
private
|
|
36
32
|
|
|
37
|
-
def
|
|
38
|
-
|
|
39
|
-
trigger_wrapper,
|
|
40
|
-
menu
|
|
41
|
-
].compact)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def trigger_wrapper
|
|
45
|
-
return unless trigger
|
|
46
|
-
|
|
47
|
-
content_tag(:div, trigger, {
|
|
48
|
-
"data-shadcn--context-menu-target": "trigger",
|
|
49
|
-
"data-action": "contextmenu->shadcn--context-menu#show:prevent"
|
|
50
|
-
})
|
|
33
|
+
def context_menu_classes
|
|
34
|
+
cn("relative inline-block", class_name)
|
|
51
35
|
end
|
|
52
36
|
|
|
53
|
-
def
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
"data-action": "keydown.escape->shadcn--context-menu#close"
|
|
37
|
+
def context_menu_data_attrs
|
|
38
|
+
{
|
|
39
|
+
controller: "shadcn--context-menu",
|
|
40
|
+
action: "keydown.escape->shadcn--context-menu#close"
|
|
58
41
|
}
|
|
59
|
-
attrs.merge!(html_options)
|
|
60
|
-
attrs.merge!(build_data)
|
|
61
|
-
attrs.compact
|
|
62
42
|
end
|
|
63
43
|
end
|
|
64
44
|
end
|
|
@@ -3,16 +3,40 @@
|
|
|
3
3
|
module Shadcn
|
|
4
4
|
# Context Menu Content component
|
|
5
5
|
class ContextMenuContentComponent < BaseComponent
|
|
6
|
-
BASE_CLASSES = "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md
|
|
6
|
+
BASE_CLASSES = "shadcn-context-menu z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md"
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
# Use polymorphic slots to preserve the order of items, labels, and separators
|
|
9
|
+
renders_many :menu_items, types: {
|
|
10
|
+
item: {
|
|
11
|
+
renders: lambda { |**options, &block|
|
|
12
|
+
ContextMenuItemComponent.new(**options, &block)
|
|
13
|
+
},
|
|
14
|
+
as: :item
|
|
15
|
+
},
|
|
16
|
+
checkbox_item: {
|
|
17
|
+
renders: lambda { |**options, &block|
|
|
18
|
+
ContextMenuCheckboxItemComponent.new(**options, &block)
|
|
19
|
+
},
|
|
20
|
+
as: :checkbox_item
|
|
21
|
+
},
|
|
22
|
+
radio_group: {
|
|
23
|
+
renders: lambda { |**options, &block|
|
|
24
|
+
ContextMenuRadioGroupComponent.new(**options, &block)
|
|
25
|
+
},
|
|
26
|
+
as: :radio_group
|
|
27
|
+
},
|
|
28
|
+
label: {
|
|
29
|
+
renders: lambda { |**options, &block|
|
|
30
|
+
ContextMenuLabelComponent.new(**options, &block)
|
|
31
|
+
},
|
|
32
|
+
as: :label
|
|
33
|
+
},
|
|
34
|
+
separator: {
|
|
35
|
+
renders: lambda { |**options|
|
|
36
|
+
ContextMenuSeparatorComponent.new(**options)
|
|
37
|
+
},
|
|
38
|
+
as: :separator
|
|
39
|
+
}
|
|
16
40
|
}
|
|
17
41
|
|
|
18
42
|
def call
|
|
@@ -22,11 +46,10 @@ module Shadcn
|
|
|
22
46
|
private
|
|
23
47
|
|
|
24
48
|
def menu_content
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
end
|
|
49
|
+
# Trigger slot evaluation first
|
|
50
|
+
content
|
|
51
|
+
# Render all menu items in the order they were added
|
|
52
|
+
safe_join(menu_items)
|
|
30
53
|
end
|
|
31
54
|
|
|
32
55
|
def menu_attributes
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
module Shadcn
|
|
4
4
|
# Context Menu Item component
|
|
5
5
|
class ContextMenuItemComponent < BaseComponent
|
|
6
|
-
BASE_CLASSES = "relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0"
|
|
6
|
+
BASE_CLASSES = "relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0"
|
|
7
7
|
|
|
8
8
|
VARIANTS = {
|
|
9
9
|
default: "",
|
|
10
|
-
destructive: "text-destructive focus:bg-destructive focus:text-destructive-foreground"
|
|
10
|
+
destructive: "text-destructive hover:bg-destructive hover:text-destructive-foreground focus:bg-destructive focus:text-destructive-foreground"
|
|
11
11
|
}.freeze
|
|
12
12
|
|
|
13
13
|
renders_one :shortcut, lambda { |**options|
|
|
@@ -53,6 +53,7 @@ module Shadcn
|
|
|
53
53
|
tabindex: @disabled ? nil : "-1",
|
|
54
54
|
href: @href,
|
|
55
55
|
"data-disabled": @disabled ? "" : nil,
|
|
56
|
+
"data-shadcn--context-menu-target": "item",
|
|
56
57
|
"data-action": "click->shadcn--context-menu#selectItem"
|
|
57
58
|
}
|
|
58
59
|
attrs.merge!(html_options)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Context Menu Radio Group component
|
|
5
|
+
# Group of mutually exclusive radio items
|
|
6
|
+
class ContextMenuRadioGroupComponent < BaseComponent
|
|
7
|
+
renders_many :items, lambda { |**options, &block|
|
|
8
|
+
ContextMenuRadioItemComponent.new(**options, &block)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
# @param value [String] Currently selected value
|
|
12
|
+
def initialize(value: nil, **options, &block)
|
|
13
|
+
super(**options, &block)
|
|
14
|
+
@value = value
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def call
|
|
18
|
+
content_tag(:div, group_content, group_attributes)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def group_content
|
|
24
|
+
if items.any?
|
|
25
|
+
safe_join(items)
|
|
26
|
+
else
|
|
27
|
+
content
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def group_attributes
|
|
32
|
+
attrs = {
|
|
33
|
+
class: class_name,
|
|
34
|
+
role: "group",
|
|
35
|
+
"data-value": @value
|
|
36
|
+
}
|
|
37
|
+
attrs.merge!(html_options)
|
|
38
|
+
attrs.merge!(build_data)
|
|
39
|
+
attrs.compact
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Context Menu Radio Item component
|
|
5
|
+
# A radio button within a radio group
|
|
6
|
+
class ContextMenuRadioItemComponent < BaseComponent
|
|
7
|
+
BASE_CLASSES = "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50"
|
|
8
|
+
|
|
9
|
+
renders_one :shortcut, lambda { |**options|
|
|
10
|
+
ContextMenuShortcutComponent.new(**options)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
# @param value [String] Value of this radio item
|
|
14
|
+
# @param checked [Boolean] Whether item is selected
|
|
15
|
+
# @param disabled [Boolean] Whether item is disabled
|
|
16
|
+
def initialize(value: nil, checked: false, disabled: false, **options, &block)
|
|
17
|
+
super(**options, &block)
|
|
18
|
+
@value = value
|
|
19
|
+
@checked = checked
|
|
20
|
+
@disabled = disabled
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def call
|
|
24
|
+
content_tag(:div, item_content, item_attributes)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def item_content
|
|
30
|
+
safe_join([
|
|
31
|
+
radio_indicator,
|
|
32
|
+
content,
|
|
33
|
+
shortcut
|
|
34
|
+
].compact)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def radio_indicator
|
|
38
|
+
content_tag(:span, radio_icon, class: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def radio_icon
|
|
42
|
+
return "" unless @checked
|
|
43
|
+
|
|
44
|
+
content_tag(:svg, circle_svg, {
|
|
45
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
46
|
+
width: "16",
|
|
47
|
+
height: "16",
|
|
48
|
+
viewBox: "0 0 24 24",
|
|
49
|
+
fill: "currentColor",
|
|
50
|
+
stroke: "none",
|
|
51
|
+
class: "h-4 w-4"
|
|
52
|
+
})
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def circle_svg
|
|
56
|
+
content_tag(:circle, "", cx: "12", cy: "12", r: "6")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def item_attributes
|
|
60
|
+
attrs = {
|
|
61
|
+
class: cn(BASE_CLASSES, class_name),
|
|
62
|
+
role: "menuitemradio",
|
|
63
|
+
"aria-checked": @checked.to_s,
|
|
64
|
+
tabindex: @disabled ? nil : "-1",
|
|
65
|
+
"data-disabled": @disabled ? "" : nil,
|
|
66
|
+
"data-state": @checked ? "checked" : "unchecked",
|
|
67
|
+
"data-value": @value,
|
|
68
|
+
"data-shadcn--context-menu-target": "item",
|
|
69
|
+
"data-action": "click->shadcn--context-menu#selectItem"
|
|
70
|
+
}
|
|
71
|
+
attrs.merge!(html_options)
|
|
72
|
+
attrs.merge!(build_data)
|
|
73
|
+
attrs.compact
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<div id="<%= @id %>"
|
|
2
|
+
class="<%= dialog_classes %>"
|
|
3
|
+
data-controller="<%= dialog_data_attrs[:controller] %>"
|
|
4
|
+
data-shadcn--dialog-open-value="<%= dialog_data_attrs[:"shadcn--dialog-open-value"] %>"
|
|
5
|
+
data-shadcn--dialog-modal-value="<%= dialog_data_attrs[:"shadcn--dialog-modal-value"] %>"
|
|
6
|
+
data-dialog-id="<%= dialog_data_attrs[:"dialog-id"] %>"
|
|
7
|
+
<%= tag_attributes %>>
|
|
8
|
+
<% if trigger? %>
|
|
9
|
+
<div data-shadcn--dialog-target="trigger" data-action="click->shadcn--dialog#open">
|
|
10
|
+
<%= trigger %>
|
|
11
|
+
</div>
|
|
12
|
+
<% end %>
|
|
13
|
+
<%= body if body? %>
|
|
14
|
+
</div>
|
|
@@ -38,40 +38,19 @@ module Shadcn
|
|
|
38
38
|
@modal = modal
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
def call
|
|
42
|
-
content_tag(:div, dialog_content, dialog_attributes)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
41
|
private
|
|
46
42
|
|
|
47
|
-
def
|
|
48
|
-
|
|
49
|
-
trigger_wrapper,
|
|
50
|
-
body
|
|
51
|
-
].compact)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def trigger_wrapper
|
|
55
|
-
return unless trigger
|
|
56
|
-
|
|
57
|
-
content_tag(:div, trigger, {
|
|
58
|
-
"data-shadcn--dialog-target": "trigger",
|
|
59
|
-
"data-action": "click->shadcn--dialog#open"
|
|
60
|
-
})
|
|
43
|
+
def dialog_classes
|
|
44
|
+
class_name
|
|
61
45
|
end
|
|
62
46
|
|
|
63
|
-
def
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"data-shadcn--dialog-modal-value": @modal.to_s,
|
|
70
|
-
"data-dialog-id": @id
|
|
47
|
+
def dialog_data_attrs
|
|
48
|
+
{
|
|
49
|
+
controller: "shadcn--dialog",
|
|
50
|
+
"shadcn--dialog-open-value": @open.to_s,
|
|
51
|
+
"shadcn--dialog-modal-value": @modal.to_s,
|
|
52
|
+
"dialog-id": @id
|
|
71
53
|
}
|
|
72
|
-
attrs.merge!(html_options)
|
|
73
|
-
attrs.merge!(build_data)
|
|
74
|
-
attrs.compact
|
|
75
54
|
end
|
|
76
55
|
end
|
|
77
56
|
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<div class="<%= drawer_classes %>"
|
|
2
|
+
data-controller="<%= drawer_data_attrs[:controller] %>"
|
|
3
|
+
data-shadcn--drawer-open-value="<%= drawer_data_attrs[:"shadcn--drawer-open-value"] %>"
|
|
4
|
+
data-shadcn--drawer-direction-value="<%= drawer_data_attrs[:"shadcn--drawer-direction-value"] %>"
|
|
5
|
+
<%= tag_attributes %>>
|
|
6
|
+
<% if trigger? %>
|
|
7
|
+
<div data-shadcn--drawer-target="trigger" data-action="click->shadcn--drawer#open">
|
|
8
|
+
<%= trigger %>
|
|
9
|
+
</div>
|
|
10
|
+
<% end %>
|
|
11
|
+
<%= body if body? %>
|
|
12
|
+
</div>
|
|
@@ -35,38 +35,18 @@ module Shadcn
|
|
|
35
35
|
@direction = direction
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
def call
|
|
39
|
-
content_tag(:div, drawer_content, drawer_attributes)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
38
|
private
|
|
43
39
|
|
|
44
|
-
def
|
|
45
|
-
|
|
46
|
-
trigger_wrapper,
|
|
47
|
-
body
|
|
48
|
-
].compact)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def trigger_wrapper
|
|
52
|
-
return unless trigger
|
|
53
|
-
|
|
54
|
-
content_tag(:div, trigger, {
|
|
55
|
-
"data-shadcn--drawer-target": "trigger",
|
|
56
|
-
"data-action": "click->shadcn--drawer#open"
|
|
57
|
-
})
|
|
40
|
+
def drawer_classes
|
|
41
|
+
class_name
|
|
58
42
|
end
|
|
59
43
|
|
|
60
|
-
def
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"data-shadcn--drawer-direction-value": @direction.to_s
|
|
44
|
+
def drawer_data_attrs
|
|
45
|
+
{
|
|
46
|
+
controller: "shadcn--drawer",
|
|
47
|
+
"shadcn--drawer-open-value": @open.to_s,
|
|
48
|
+
"shadcn--drawer-direction-value": @direction.to_s
|
|
66
49
|
}
|
|
67
|
-
attrs.merge!(html_options)
|
|
68
|
-
attrs.merge!(build_data)
|
|
69
|
-
attrs.compact
|
|
70
50
|
end
|
|
71
51
|
end
|
|
72
52
|
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Dropdown Menu Checkbox Item component
|
|
5
|
+
# A menu item that can be checked/unchecked
|
|
6
|
+
class DropdownMenuCheckboxItemComponent < BaseComponent
|
|
7
|
+
BASE_CLASSES = "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50"
|
|
8
|
+
|
|
9
|
+
renders_one :shortcut, lambda { |**options|
|
|
10
|
+
DropdownMenuShortcutComponent.new(**options)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
# @param checked [Boolean] Whether item is checked
|
|
14
|
+
# @param disabled [Boolean] Whether item is disabled
|
|
15
|
+
def initialize(checked: false, disabled: false, **options, &block)
|
|
16
|
+
super(**options, &block)
|
|
17
|
+
@checked = checked
|
|
18
|
+
@disabled = disabled
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def call
|
|
22
|
+
content_tag(:div, item_content, item_attributes)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def item_content
|
|
28
|
+
safe_join([
|
|
29
|
+
check_indicator,
|
|
30
|
+
content,
|
|
31
|
+
shortcut
|
|
32
|
+
].compact)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def check_indicator
|
|
36
|
+
content_tag(:span, check_icon, class: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def check_icon
|
|
40
|
+
return "" unless @checked
|
|
41
|
+
|
|
42
|
+
content_tag(:svg, check_svg_path, {
|
|
43
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
44
|
+
width: "16",
|
|
45
|
+
height: "16",
|
|
46
|
+
viewBox: "0 0 24 24",
|
|
47
|
+
fill: "none",
|
|
48
|
+
stroke: "currentColor",
|
|
49
|
+
"stroke-width": "2",
|
|
50
|
+
"stroke-linecap": "round",
|
|
51
|
+
"stroke-linejoin": "round",
|
|
52
|
+
class: "h-4 w-4"
|
|
53
|
+
})
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def check_svg_path
|
|
57
|
+
content_tag(:polyline, "", points: "20 6 9 17 4 12")
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def item_attributes
|
|
61
|
+
attrs = {
|
|
62
|
+
class: cn(BASE_CLASSES, class_name),
|
|
63
|
+
role: "menuitemcheckbox",
|
|
64
|
+
"aria-checked": @checked.to_s,
|
|
65
|
+
tabindex: @disabled ? nil : "-1",
|
|
66
|
+
"data-disabled": @disabled ? "" : nil,
|
|
67
|
+
"data-state": @checked ? "checked" : "unchecked",
|
|
68
|
+
"data-shadcn--dropdown-target": "item",
|
|
69
|
+
"data-action": "click->shadcn--dropdown#toggleCheckbox"
|
|
70
|
+
}
|
|
71
|
+
attrs.merge!(html_options)
|
|
72
|
+
attrs.merge!(build_data)
|
|
73
|
+
attrs.compact
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<div class="<%= dropdown_classes %>"
|
|
2
|
+
data-controller="<%= dropdown_data_attrs[:controller] %>"
|
|
3
|
+
data-shadcn--dropdown-open-value="<%= dropdown_data_attrs[:"shadcn--dropdown-open-value"] %>"
|
|
4
|
+
data-shadcn--dropdown-align-value="<%= dropdown_data_attrs[:"shadcn--dropdown-align-value"] %>"
|
|
5
|
+
data-shadcn--dropdown-side-value="<%= dropdown_data_attrs[:"shadcn--dropdown-side-value"] %>"
|
|
6
|
+
data-action="<%= dropdown_data_attrs[:action] %>"
|
|
7
|
+
<%= tag_attributes %>>
|
|
8
|
+
<% if trigger? %>
|
|
9
|
+
<div data-shadcn--dropdown-target="trigger" data-action="click->shadcn--dropdown#toggle">
|
|
10
|
+
<%= trigger %>
|
|
11
|
+
</div>
|
|
12
|
+
<% end %>
|
|
13
|
+
<%= menu if menu? %>
|
|
14
|
+
</div>
|
|
@@ -36,40 +36,20 @@ module Shadcn
|
|
|
36
36
|
@side = side
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
-
def call
|
|
40
|
-
content_tag(:div, dropdown_content, dropdown_attributes)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
39
|
private
|
|
44
40
|
|
|
45
|
-
def
|
|
46
|
-
|
|
47
|
-
trigger_wrapper,
|
|
48
|
-
menu
|
|
49
|
-
].compact)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def trigger_wrapper
|
|
53
|
-
return unless trigger
|
|
54
|
-
|
|
55
|
-
content_tag(:div, trigger, {
|
|
56
|
-
"data-shadcn--dropdown-target": "trigger",
|
|
57
|
-
"data-action": "click->shadcn--dropdown#toggle"
|
|
58
|
-
})
|
|
41
|
+
def dropdown_classes
|
|
42
|
+
cn("relative inline-block", class_name)
|
|
59
43
|
end
|
|
60
44
|
|
|
61
|
-
def
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"data-action": "keydown.escape->shadcn--dropdown#close clickOutside->shadcn--dropdown#close"
|
|
45
|
+
def dropdown_data_attrs
|
|
46
|
+
{
|
|
47
|
+
controller: "shadcn--dropdown",
|
|
48
|
+
"shadcn--dropdown-open-value": @open.to_s,
|
|
49
|
+
"shadcn--dropdown-align-value": @align.to_s,
|
|
50
|
+
"shadcn--dropdown-side-value": @side.to_s,
|
|
51
|
+
action: "keydown.escape->shadcn--dropdown#close clickOutside->shadcn--dropdown#close"
|
|
69
52
|
}
|
|
70
|
-
attrs.merge!(html_options)
|
|
71
|
-
attrs.merge!(build_data)
|
|
72
|
-
attrs.compact
|
|
73
53
|
end
|
|
74
54
|
end
|
|
75
55
|
end
|
|
@@ -5,17 +5,44 @@ module Shadcn
|
|
|
5
5
|
class DropdownMenuContentComponent < BaseComponent
|
|
6
6
|
BASE_CLASSES = "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2"
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
8
|
+
# Use polymorphic slots to preserve the order of items, labels, separators, groups, etc.
|
|
9
|
+
renders_many :menu_items, types: {
|
|
10
|
+
item: {
|
|
11
|
+
renders: lambda { |**options, &block|
|
|
12
|
+
DropdownMenuItemComponent.new(**options, &block)
|
|
13
|
+
},
|
|
14
|
+
as: :item
|
|
15
|
+
},
|
|
16
|
+
label: {
|
|
17
|
+
renders: lambda { |**options, &block|
|
|
18
|
+
DropdownMenuLabelComponent.new(**options, &block)
|
|
19
|
+
},
|
|
20
|
+
as: :label
|
|
21
|
+
},
|
|
22
|
+
separator: {
|
|
23
|
+
renders: lambda { |**options|
|
|
24
|
+
DropdownMenuSeparatorComponent.new(**options)
|
|
25
|
+
},
|
|
26
|
+
as: :separator
|
|
27
|
+
},
|
|
28
|
+
group: {
|
|
29
|
+
renders: lambda { |**options, &block|
|
|
30
|
+
DropdownMenuGroupComponent.new(**options, &block)
|
|
31
|
+
},
|
|
32
|
+
as: :group
|
|
33
|
+
},
|
|
34
|
+
checkbox_item: {
|
|
35
|
+
renders: lambda { |**options, &block|
|
|
36
|
+
DropdownMenuCheckboxItemComponent.new(**options, &block)
|
|
37
|
+
},
|
|
38
|
+
as: :checkbox_item
|
|
39
|
+
},
|
|
40
|
+
radio_group: {
|
|
41
|
+
renders: lambda { |**options, &block|
|
|
42
|
+
DropdownMenuRadioGroupComponent.new(**options, &block)
|
|
43
|
+
},
|
|
44
|
+
as: :radio_group
|
|
45
|
+
}
|
|
19
46
|
}
|
|
20
47
|
|
|
21
48
|
def call
|
|
@@ -25,12 +52,14 @@ module Shadcn
|
|
|
25
52
|
private
|
|
26
53
|
|
|
27
54
|
def menu_content
|
|
28
|
-
#
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
55
|
+
# Trigger slot evaluation first by accessing content
|
|
56
|
+
raw_content = content
|
|
57
|
+
# If polymorphic slots were used, render them in order
|
|
58
|
+
if menu_items.any?
|
|
59
|
+
safe_join(menu_items)
|
|
32
60
|
else
|
|
33
|
-
content
|
|
61
|
+
# Otherwise render the raw block content (for backwards compatibility)
|
|
62
|
+
raw_content
|
|
34
63
|
end
|
|
35
64
|
end
|
|
36
65
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Dropdown Menu Radio Group component
|
|
5
|
+
# Group of mutually exclusive radio items
|
|
6
|
+
class DropdownMenuRadioGroupComponent < BaseComponent
|
|
7
|
+
renders_many :items, lambda { |**options, &block|
|
|
8
|
+
DropdownMenuRadioItemComponent.new(**options, &block)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
# @param value [String] Currently selected value
|
|
12
|
+
def initialize(value: nil, **options, &block)
|
|
13
|
+
super(**options, &block)
|
|
14
|
+
@value = value
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def call
|
|
18
|
+
content_tag(:div, group_content, group_attributes)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def group_content
|
|
24
|
+
if items.any?
|
|
25
|
+
safe_join(items)
|
|
26
|
+
else
|
|
27
|
+
content
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def group_attributes
|
|
32
|
+
attrs = {
|
|
33
|
+
class: class_name,
|
|
34
|
+
role: "group",
|
|
35
|
+
"data-value": @value
|
|
36
|
+
}
|
|
37
|
+
attrs.merge!(html_options)
|
|
38
|
+
attrs.merge!(build_data)
|
|
39
|
+
attrs.compact
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|