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
|
@@ -36,41 +36,21 @@ module Shadcn
|
|
|
36
36
|
@modal = modal
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
-
def call
|
|
40
|
-
content_tag(:div, popover_structure, popover_attributes)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
39
|
private
|
|
44
40
|
|
|
45
|
-
def
|
|
46
|
-
|
|
47
|
-
trigger_wrapper,
|
|
48
|
-
body
|
|
49
|
-
].compact)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def trigger_wrapper
|
|
53
|
-
return unless trigger
|
|
54
|
-
|
|
55
|
-
content_tag(:div, trigger, {
|
|
56
|
-
"data-shadcn--popover-target": "trigger",
|
|
57
|
-
"data-action": "click->shadcn--popover#toggle"
|
|
58
|
-
})
|
|
41
|
+
def popover_classes
|
|
42
|
+
cn("relative inline-block", class_name)
|
|
59
43
|
end
|
|
60
44
|
|
|
61
|
-
def
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"data-action": "keydown.escape->shadcn--popover#close"
|
|
45
|
+
def popover_data_attrs
|
|
46
|
+
{
|
|
47
|
+
controller: "shadcn--popover",
|
|
48
|
+
"shadcn--popover-open-value": @open.to_s,
|
|
49
|
+
"shadcn--popover-side-value": @side.to_s,
|
|
50
|
+
"shadcn--popover-align-value": @align.to_s,
|
|
51
|
+
"shadcn--popover-modal-value": @modal.to_s,
|
|
52
|
+
action: "keydown.escape->shadcn--popover#close"
|
|
70
53
|
}
|
|
71
|
-
attrs.merge!(html_options)
|
|
72
|
-
attrs.merge!(build_data)
|
|
73
|
-
attrs.compact
|
|
74
54
|
end
|
|
75
55
|
end
|
|
76
56
|
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<div class="<%= progress_classes %>"
|
|
2
|
+
role="progressbar"
|
|
3
|
+
aria-valuemin="0"
|
|
4
|
+
aria-valuemax="<%= @max %>"<% unless @indeterminate %>
|
|
5
|
+
aria-valuenow="<%= @value %>"<% end %>
|
|
6
|
+
data-state="<%= data_state %>"<% if @value %>
|
|
7
|
+
data-value="<%= @value %>"<% end %>
|
|
8
|
+
data-max="<%= @max %>"
|
|
9
|
+
<%= tag_attributes %>>
|
|
10
|
+
<div class="<%= indicator_classes %>"<% if indicator_style %>
|
|
11
|
+
style="<%= indicator_style %>"<% end %>
|
|
12
|
+
data-state="<%= data_state %>"></div>
|
|
13
|
+
</div>
|
|
@@ -27,14 +27,10 @@ module Shadcn
|
|
|
27
27
|
@indeterminate = indeterminate
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
def call
|
|
31
|
-
content_tag(:div, progress_indicator, progress_attributes)
|
|
32
|
-
end
|
|
33
|
-
|
|
34
30
|
private
|
|
35
31
|
|
|
36
|
-
def
|
|
37
|
-
|
|
32
|
+
def progress_classes
|
|
33
|
+
merge_classes(BASE_CLASSES)
|
|
38
34
|
end
|
|
39
35
|
|
|
40
36
|
def progress_percentage
|
|
@@ -50,28 +46,12 @@ module Shadcn
|
|
|
50
46
|
end
|
|
51
47
|
end
|
|
52
48
|
|
|
53
|
-
def
|
|
54
|
-
|
|
55
|
-
class: merge_classes(BASE_CLASSES),
|
|
56
|
-
role: "progressbar",
|
|
57
|
-
"aria-valuemin": 0,
|
|
58
|
-
"aria-valuemax": @max,
|
|
59
|
-
"aria-valuenow": @indeterminate ? nil : @value,
|
|
60
|
-
"data-state": @indeterminate ? "indeterminate" : "determinate",
|
|
61
|
-
"data-value": @value,
|
|
62
|
-
"data-max": @max
|
|
63
|
-
}
|
|
64
|
-
attrs.merge!(html_options)
|
|
65
|
-
attrs.merge!(build_data)
|
|
66
|
-
attrs.compact
|
|
49
|
+
def indicator_classes
|
|
50
|
+
cn(INDICATOR_CLASSES, @indeterminate ? "animate-progress-indeterminate" : "")
|
|
67
51
|
end
|
|
68
52
|
|
|
69
|
-
def
|
|
70
|
-
|
|
71
|
-
class: cn(INDICATOR_CLASSES, @indeterminate ? "animate-progress-indeterminate" : ""),
|
|
72
|
-
style: indicator_style,
|
|
73
|
-
"data-state": @indeterminate ? "indeterminate" : "determinate"
|
|
74
|
-
}
|
|
53
|
+
def data_state
|
|
54
|
+
@indeterminate ? "indeterminate" : "determinate"
|
|
75
55
|
end
|
|
76
56
|
end
|
|
77
57
|
end
|
|
@@ -70,13 +70,20 @@ module Shadcn
|
|
|
70
70
|
@orientation = orientation
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
def group_classes
|
|
76
|
+
cn(BASE_CLASSES, orientation_classes, class_name)
|
|
77
77
|
end
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
def orientation_classes
|
|
80
|
+
case @orientation
|
|
81
|
+
when :horizontal
|
|
82
|
+
"flex flex-row gap-4"
|
|
83
|
+
else
|
|
84
|
+
"grid gap-3"
|
|
85
|
+
end
|
|
86
|
+
end
|
|
80
87
|
|
|
81
88
|
# Render items from the items: data array
|
|
82
89
|
def render_data_items
|
|
@@ -104,26 +111,5 @@ module Shadcn
|
|
|
104
111
|
def generate_item_id(value)
|
|
105
112
|
"#{@name}-#{value}".parameterize
|
|
106
113
|
end
|
|
107
|
-
|
|
108
|
-
def group_attributes
|
|
109
|
-
attrs = {
|
|
110
|
-
role: "radiogroup",
|
|
111
|
-
class: cn(BASE_CLASSES, orientation_classes, class_name),
|
|
112
|
-
"aria-required": @required ? "true" : nil,
|
|
113
|
-
"aria-disabled": @disabled ? "true" : nil
|
|
114
|
-
}
|
|
115
|
-
attrs.merge!(html_options)
|
|
116
|
-
attrs.merge!(build_data)
|
|
117
|
-
attrs.compact
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
def orientation_classes
|
|
121
|
-
case @orientation
|
|
122
|
-
when :horizontal
|
|
123
|
-
"flex flex-row gap-4"
|
|
124
|
-
else
|
|
125
|
-
"grid gap-3"
|
|
126
|
-
end
|
|
127
|
-
end
|
|
128
114
|
end
|
|
129
115
|
end
|
|
@@ -8,6 +8,9 @@ module Shadcn
|
|
|
8
8
|
# @example With label parameter (Tier 2 API)
|
|
9
9
|
# <%= group.with_item(value: "free", label: "Free") %>
|
|
10
10
|
#
|
|
11
|
+
# @example With label and description
|
|
12
|
+
# <%= group.with_item(value: "pro", label: "Pro", description: "For professional developers") %>
|
|
13
|
+
#
|
|
11
14
|
# @example With block content (backward compatible)
|
|
12
15
|
# <%= group.with_item(value: "free") { "Free" } %>
|
|
13
16
|
#
|
|
@@ -36,10 +39,12 @@ module Shadcn
|
|
|
36
39
|
].join(" ")
|
|
37
40
|
|
|
38
41
|
LABEL_CLASSES = "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
|
42
|
+
DESCRIPTION_CLASSES = "text-sm text-muted-foreground"
|
|
39
43
|
|
|
40
44
|
# @param value [String] The value for this radio option
|
|
41
45
|
# @param id [String, nil] HTML id attribute
|
|
42
46
|
# @param label [String, nil] Label text (alternative to block content)
|
|
47
|
+
# @param description [String, nil] Description text displayed below the label
|
|
43
48
|
# @param disabled [Boolean] Whether this option is disabled
|
|
44
49
|
# @param group_name [String, nil] The name attribute from parent group
|
|
45
50
|
# @param selected [Boolean] Whether this option is selected
|
|
@@ -47,6 +52,7 @@ module Shadcn
|
|
|
47
52
|
value:,
|
|
48
53
|
id: nil,
|
|
49
54
|
label: nil,
|
|
55
|
+
description: nil,
|
|
50
56
|
disabled: false,
|
|
51
57
|
group_name: nil,
|
|
52
58
|
selected: false,
|
|
@@ -57,6 +63,7 @@ module Shadcn
|
|
|
57
63
|
@value = value
|
|
58
64
|
@id = id || "radio-#{value}"
|
|
59
65
|
@label = label
|
|
66
|
+
@description = description
|
|
60
67
|
@disabled = disabled
|
|
61
68
|
@group_name = group_name
|
|
62
69
|
@selected = selected
|
|
@@ -66,12 +73,17 @@ module Shadcn
|
|
|
66
73
|
label_text = @label || content.presence
|
|
67
74
|
|
|
68
75
|
if label_text.present?
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
76
|
+
if @description.present?
|
|
77
|
+
# Render with label and description
|
|
78
|
+
render_with_description(label_text)
|
|
79
|
+
else
|
|
80
|
+
# Render with integrated label only
|
|
81
|
+
content_tag(:label, label_wrapper_attributes) do
|
|
82
|
+
safe_join([
|
|
83
|
+
radio_input,
|
|
84
|
+
content_tag(:span, label_text, class: LABEL_CLASSES)
|
|
85
|
+
])
|
|
86
|
+
end
|
|
75
87
|
end
|
|
76
88
|
else
|
|
77
89
|
# Render just the radio input (for use with external labels)
|
|
@@ -81,6 +93,20 @@ module Shadcn
|
|
|
81
93
|
|
|
82
94
|
private
|
|
83
95
|
|
|
96
|
+
def render_with_description(label_text)
|
|
97
|
+
content_tag(:div, class: "flex items-start space-x-3") do
|
|
98
|
+
safe_join([
|
|
99
|
+
content_tag(:div, class: "mt-0.5") { radio_input },
|
|
100
|
+
content_tag(:div, class: "grid gap-1.5 leading-none") do
|
|
101
|
+
safe_join([
|
|
102
|
+
content_tag(:label, label_text, class: cn(LABEL_CLASSES, "cursor-pointer"), for: @id),
|
|
103
|
+
content_tag(:p, @description, class: DESCRIPTION_CLASSES)
|
|
104
|
+
])
|
|
105
|
+
end
|
|
106
|
+
])
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
84
110
|
def radio_input
|
|
85
111
|
tag(:input, input_attributes)
|
|
86
112
|
end
|
|
@@ -32,22 +32,30 @@ module Shadcn
|
|
|
32
32
|
# <% end %>
|
|
33
33
|
#
|
|
34
34
|
class ResizablePanelGroupComponent < BaseComponent
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
min_size:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
35
|
+
# Use polymorphic slots to preserve the order of panels and handles
|
|
36
|
+
renders_many :items, types: {
|
|
37
|
+
panel: {
|
|
38
|
+
renders: lambda { |default_size: nil, min_size: nil, max_size: nil, **options|
|
|
39
|
+
ResizablePanelComponent.new(
|
|
40
|
+
default_size: default_size,
|
|
41
|
+
min_size: min_size,
|
|
42
|
+
max_size: max_size,
|
|
43
|
+
direction: @direction,
|
|
44
|
+
**options
|
|
45
|
+
)
|
|
46
|
+
},
|
|
47
|
+
as: :panel
|
|
48
|
+
},
|
|
49
|
+
handle: {
|
|
50
|
+
renders: lambda { |with_handle: false, **options|
|
|
51
|
+
ResizableHandleComponent.new(
|
|
52
|
+
with_handle: with_handle,
|
|
53
|
+
direction: @direction,
|
|
54
|
+
**options
|
|
55
|
+
)
|
|
56
|
+
},
|
|
57
|
+
as: :handle
|
|
58
|
+
}
|
|
51
59
|
}
|
|
52
60
|
|
|
53
61
|
DIRECTIONS = {
|
|
@@ -70,7 +78,10 @@ module Shadcn
|
|
|
70
78
|
private
|
|
71
79
|
|
|
72
80
|
def group_content
|
|
81
|
+
# Trigger slot evaluation first
|
|
73
82
|
content
|
|
83
|
+
# Render all items in the order they were added
|
|
84
|
+
safe_join(items)
|
|
74
85
|
end
|
|
75
86
|
|
|
76
87
|
def group_attributes
|
|
@@ -33,12 +33,12 @@ module Shadcn
|
|
|
33
33
|
@type = type.to_sym
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
def call
|
|
37
|
-
content_tag(:div, scroll_structure, scroll_attributes)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
36
|
private
|
|
41
37
|
|
|
38
|
+
def scroll_classes
|
|
39
|
+
merge_classes(BASE_CLASSES)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
42
|
def scroll_structure
|
|
43
43
|
safe_join([
|
|
44
44
|
viewport,
|
|
@@ -94,17 +94,5 @@ module Shadcn
|
|
|
94
94
|
|
|
95
95
|
content_tag(:div, "", class: "absolute right-0 bottom-0 h-2.5 w-2.5 bg-transparent")
|
|
96
96
|
end
|
|
97
|
-
|
|
98
|
-
def scroll_attributes
|
|
99
|
-
attrs = {
|
|
100
|
-
class: merge_classes(BASE_CLASSES),
|
|
101
|
-
"data-controller": "shadcn--scroll-area",
|
|
102
|
-
"data-shadcn--scroll-area-orientation-value": @orientation.to_s,
|
|
103
|
-
"data-shadcn--scroll-area-type-value": @type.to_s
|
|
104
|
-
}
|
|
105
|
-
attrs.merge!(html_options)
|
|
106
|
-
attrs.merge!(build_data)
|
|
107
|
-
attrs.compact
|
|
108
|
-
end
|
|
109
97
|
end
|
|
110
98
|
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<div class="<%= wrapper_classes %>"
|
|
2
|
+
data-controller="shadcn--select"
|
|
3
|
+
data-shadcn--select-value-value="<%= @value %>"
|
|
4
|
+
data-action="keydown.escape->shadcn--select#close"
|
|
5
|
+
<%= tag_attributes %>>
|
|
6
|
+
<input type="hidden"
|
|
7
|
+
<%= "name=\"#{ERB::Util.html_escape_once(@name)}\"".html_safe if @name %>
|
|
8
|
+
<%= "id=\"#{ERB::Util.html_escape_once(@id)}\"".html_safe if @id %>
|
|
9
|
+
<%= "value=\"#{ERB::Util.html_escape_once(@value)}\"".html_safe if @value %>
|
|
10
|
+
<%= "required" if @required %>
|
|
11
|
+
data-shadcn--select-target="input" />
|
|
12
|
+
|
|
13
|
+
<button type="button"
|
|
14
|
+
class="<%= trigger_classes %>"
|
|
15
|
+
role="combobox"
|
|
16
|
+
<%= "disabled" if @disabled %>
|
|
17
|
+
aria-expanded="false"
|
|
18
|
+
aria-haspopup="listbox"
|
|
19
|
+
data-shadcn--select-target="trigger"
|
|
20
|
+
data-action="click->shadcn--select#toggle keydown->shadcn--select#handleKeydown"
|
|
21
|
+
data-placeholder="<%= @placeholder %>">
|
|
22
|
+
<span data-shadcn--select-target="display"><%= display_text %></span>
|
|
23
|
+
<svg xmlns="http://www.w3.org/2000/svg"
|
|
24
|
+
width="16"
|
|
25
|
+
height="16"
|
|
26
|
+
viewBox="0 0 24 24"
|
|
27
|
+
fill="none"
|
|
28
|
+
class="h-4 w-4 opacity-50">
|
|
29
|
+
<path d="m6 9 6 6 6-6"
|
|
30
|
+
stroke="currentColor"
|
|
31
|
+
stroke-width="2"
|
|
32
|
+
stroke-linecap="round"
|
|
33
|
+
stroke-linejoin="round" />
|
|
34
|
+
</svg>
|
|
35
|
+
</button>
|
|
36
|
+
|
|
37
|
+
<div class="<%= CONTENT_CLASSES %>"
|
|
38
|
+
role="listbox"
|
|
39
|
+
data-shadcn--select-target="content"
|
|
40
|
+
data-state="closed"
|
|
41
|
+
hidden>
|
|
42
|
+
<div class="<%= VIEWPORT_CLASSES %>">
|
|
43
|
+
<%= items_content %>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
@@ -25,11 +25,20 @@ module Shadcn
|
|
|
25
25
|
CONTENT_CLASSES = "absolute left-0 top-full z-50 mt-1 max-h-96 min-w-[var(--radix-select-trigger-width)] w-max overflow-hidden rounded-md border bg-popover 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"
|
|
26
26
|
VIEWPORT_CLASSES = "p-1"
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
# Use polymorphic slots to preserve the order of items and groups
|
|
29
|
+
renders_many :select_items, types: {
|
|
30
|
+
item: {
|
|
31
|
+
renders: lambda { |value:, **options, &block|
|
|
32
|
+
SelectItemComponent.new(value: value, **options, &block)
|
|
33
|
+
},
|
|
34
|
+
as: :item
|
|
35
|
+
},
|
|
36
|
+
group: {
|
|
37
|
+
renders: lambda { |label: nil, **options, &block|
|
|
38
|
+
SelectGroupComponent.new(label: label, **options, &block)
|
|
39
|
+
},
|
|
40
|
+
as: :group
|
|
41
|
+
}
|
|
33
42
|
}
|
|
34
43
|
|
|
35
44
|
# @param name [String, nil] Form field name
|
|
@@ -56,96 +65,30 @@ module Shadcn
|
|
|
56
65
|
@required = required
|
|
57
66
|
end
|
|
58
67
|
|
|
59
|
-
def call
|
|
60
|
-
content_tag(:div, select_structure, select_attributes)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
68
|
private
|
|
64
69
|
|
|
65
|
-
def
|
|
66
|
-
|
|
67
|
-
hidden_input,
|
|
68
|
-
trigger,
|
|
69
|
-
content_wrapper
|
|
70
|
-
])
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def hidden_input
|
|
74
|
-
tag(:input,
|
|
75
|
-
type: "hidden",
|
|
76
|
-
name: @name,
|
|
77
|
-
id: @id,
|
|
78
|
-
value: @value,
|
|
79
|
-
required: @required || nil,
|
|
80
|
-
"data-shadcn--select-target": "input"
|
|
81
|
-
)
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def trigger
|
|
85
|
-
content_tag(:button, trigger_content, trigger_attributes)
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def trigger_content
|
|
89
|
-
safe_join([
|
|
90
|
-
content_tag(:span, @value.presence || @placeholder, "data-shadcn--select-target": "display"),
|
|
91
|
-
chevron_icon
|
|
92
|
-
])
|
|
70
|
+
def wrapper_classes
|
|
71
|
+
cn("relative inline-block", class_name)
|
|
93
72
|
end
|
|
94
73
|
|
|
95
|
-
def
|
|
96
|
-
|
|
97
|
-
content_tag(:path, nil, d: "m6 9 6 6 6-6", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round"),
|
|
98
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
99
|
-
width: "16",
|
|
100
|
-
height: "16",
|
|
101
|
-
viewBox: "0 0 24 24",
|
|
102
|
-
fill: "none",
|
|
103
|
-
class: "h-4 w-4 opacity-50"
|
|
104
|
-
)
|
|
74
|
+
def trigger_classes
|
|
75
|
+
cn(TRIGGER_CLASSES, class_name)
|
|
105
76
|
end
|
|
106
77
|
|
|
107
|
-
def
|
|
108
|
-
|
|
109
|
-
type: "button",
|
|
110
|
-
class: cn(TRIGGER_CLASSES, class_name),
|
|
111
|
-
role: "combobox",
|
|
112
|
-
disabled: @disabled || nil,
|
|
113
|
-
"aria-expanded": "false",
|
|
114
|
-
"aria-haspopup": "listbox",
|
|
115
|
-
"data-shadcn--select-target": "trigger",
|
|
116
|
-
"data-action": "click->shadcn--select#toggle keydown->shadcn--select#handleKeydown",
|
|
117
|
-
"data-placeholder": @placeholder
|
|
118
|
-
}
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
def content_wrapper
|
|
122
|
-
content_tag(:div, viewport, {
|
|
123
|
-
class: CONTENT_CLASSES,
|
|
124
|
-
role: "listbox",
|
|
125
|
-
"data-shadcn--select-target": "content",
|
|
126
|
-
"data-state": "closed",
|
|
127
|
-
hidden: true
|
|
128
|
-
})
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
def viewport
|
|
132
|
-
content_tag(:div, items_content, class: VIEWPORT_CLASSES)
|
|
78
|
+
def display_text
|
|
79
|
+
@value.presence || @placeholder
|
|
133
80
|
end
|
|
134
81
|
|
|
135
82
|
def items_content
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
attrs.merge!(html_options.except(:class))
|
|
147
|
-
attrs.merge!(build_data)
|
|
148
|
-
attrs.compact
|
|
83
|
+
# Trigger slot evaluation first by accessing content
|
|
84
|
+
raw_content = content
|
|
85
|
+
# If polymorphic slots were used, render them in order
|
|
86
|
+
if select_items.any?
|
|
87
|
+
safe_join(select_items)
|
|
88
|
+
else
|
|
89
|
+
# Otherwise render the raw block content (for backwards compatibility)
|
|
90
|
+
raw_content
|
|
91
|
+
end
|
|
149
92
|
end
|
|
150
93
|
end
|
|
151
94
|
end
|
|
@@ -29,26 +29,18 @@ module Shadcn
|
|
|
29
29
|
@decorative = decorative
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
def call
|
|
33
|
-
tag.div(**separator_attributes)
|
|
34
|
-
end
|
|
35
|
-
|
|
36
32
|
private
|
|
37
33
|
|
|
38
34
|
def separator_classes
|
|
39
35
|
cn(BASE_CLASSES, ORIENTATIONS[@orientation], class_name)
|
|
40
36
|
end
|
|
41
37
|
|
|
42
|
-
def
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
attrs.merge!(html_options)
|
|
50
|
-
attrs.merge!(build_data)
|
|
51
|
-
attrs.compact
|
|
38
|
+
def separator_role
|
|
39
|
+
@decorative ? "none" : "separator"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def aria_orientation
|
|
43
|
+
@decorative ? nil : @orientation.to_s
|
|
52
44
|
end
|
|
53
45
|
end
|
|
54
46
|
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<div class="<%= sheet_classes %>"
|
|
2
|
+
data-controller="<%= sheet_data_attrs[:controller] %>"
|
|
3
|
+
data-shadcn--sheet-open-value="<%= sheet_data_attrs[:"shadcn--sheet-open-value"] %>"
|
|
4
|
+
data-shadcn--sheet-side-value="<%= sheet_data_attrs[:"shadcn--sheet-side-value"] %>"
|
|
5
|
+
<%= tag_attributes %>>
|
|
6
|
+
<% if trigger? %>
|
|
7
|
+
<div data-shadcn--sheet-target="trigger" data-action="click->shadcn--sheet#open">
|
|
8
|
+
<%= trigger %>
|
|
9
|
+
</div>
|
|
10
|
+
<% end %>
|
|
11
|
+
<%= body if body? %>
|
|
12
|
+
</div>
|
|
@@ -45,38 +45,18 @@ module Shadcn
|
|
|
45
45
|
@open = open
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
def call
|
|
49
|
-
content_tag(:div, sheet_structure, sheet_attributes)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
48
|
private
|
|
53
49
|
|
|
54
|
-
def
|
|
55
|
-
|
|
56
|
-
trigger_wrapper,
|
|
57
|
-
body
|
|
58
|
-
].compact)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def trigger_wrapper
|
|
62
|
-
return unless trigger
|
|
63
|
-
|
|
64
|
-
content_tag(:div, trigger, {
|
|
65
|
-
"data-shadcn--sheet-target": "trigger",
|
|
66
|
-
"data-action": "click->shadcn--sheet#open"
|
|
67
|
-
})
|
|
50
|
+
def sheet_classes
|
|
51
|
+
class_name
|
|
68
52
|
end
|
|
69
53
|
|
|
70
|
-
def
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"data-shadcn--sheet-side-value": @side.to_s
|
|
54
|
+
def sheet_data_attrs
|
|
55
|
+
{
|
|
56
|
+
controller: "shadcn--sheet",
|
|
57
|
+
"shadcn--sheet-open-value": @open.to_s,
|
|
58
|
+
"shadcn--sheet-side-value": @side.to_s
|
|
76
59
|
}
|
|
77
|
-
attrs.merge!(html_options)
|
|
78
|
-
attrs.merge!(build_data)
|
|
79
|
-
attrs.compact
|
|
80
60
|
end
|
|
81
61
|
end
|
|
82
62
|
end
|
|
@@ -86,12 +86,12 @@ module Shadcn
|
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
def call
|
|
89
|
-
content_tag(:aside,
|
|
89
|
+
content_tag(:aside, sidebar_wrapper, sidebar_attributes)
|
|
90
90
|
end
|
|
91
91
|
|
|
92
92
|
private
|
|
93
93
|
|
|
94
|
-
def
|
|
94
|
+
def sidebar_wrapper
|
|
95
95
|
safe_join([
|
|
96
96
|
sidebar_inner
|
|
97
97
|
].compact)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<div class="<%= skeleton_classes %>" <%= tag_attributes %>><%= content %></div>
|