shadcn-phlex 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 +195 -0
- data/app.css +20 -0
- data/css/shadcn-source.css +3 -0
- data/css/shadcn-tailwind.css +160 -0
- data/css/themes/mauve.css +62 -0
- data/css/themes/mist.css +62 -0
- data/css/themes/neutral.css +74 -0
- data/css/themes/olive.css +62 -0
- data/css/themes/stone.css +62 -0
- data/css/themes/taupe.css +62 -0
- data/css/themes/zinc.css +62 -0
- data/js/controllers/accordion_controller.js +135 -0
- data/js/controllers/checkbox_controller.js +52 -0
- data/js/controllers/collapsible_controller.js +85 -0
- data/js/controllers/combobox_controller.js +168 -0
- data/js/controllers/command_controller.js +171 -0
- data/js/controllers/context_menu_controller.js +132 -0
- data/js/controllers/dark_mode_controller.js +106 -0
- data/js/controllers/dialog_controller.js +205 -0
- data/js/controllers/drawer_controller.js +161 -0
- data/js/controllers/dropdown_menu_controller.js +189 -0
- data/js/controllers/hover_card_controller.js +85 -0
- data/js/controllers/index.js +89 -0
- data/js/controllers/menubar_controller.js +171 -0
- data/js/controllers/navigation_menu_controller.js +160 -0
- data/js/controllers/popover_controller.js +151 -0
- data/js/controllers/radio_group_controller.js +78 -0
- data/js/controllers/scroll_area_controller.js +117 -0
- data/js/controllers/select_controller.js +198 -0
- data/js/controllers/sheet_controller.js +130 -0
- data/js/controllers/slider_controller.js +142 -0
- data/js/controllers/switch_controller.js +40 -0
- data/js/controllers/tabs_controller.js +96 -0
- data/js/controllers/toast_controller.js +206 -0
- data/js/controllers/toggle_controller.js +30 -0
- data/js/controllers/toggle_group_controller.js +73 -0
- data/js/controllers/tooltip_controller.js +146 -0
- data/lib/generators/shadcn_phlex/component_generator.rb +79 -0
- data/lib/generators/shadcn_phlex/install_generator.rb +217 -0
- data/lib/shadcn/base.rb +27 -0
- data/lib/shadcn/engine.rb +24 -0
- data/lib/shadcn/kit.rb +1158 -0
- data/lib/shadcn/themes/accent_colors.rb +106 -0
- data/lib/shadcn/themes/base_colors.rb +313 -0
- data/lib/shadcn/ui/accordion.rb +135 -0
- data/lib/shadcn/ui/alert.rb +79 -0
- data/lib/shadcn/ui/alert_dialog.rb +220 -0
- data/lib/shadcn/ui/aspect_ratio.rb +35 -0
- data/lib/shadcn/ui/avatar.rb +134 -0
- data/lib/shadcn/ui/badge.rb +48 -0
- data/lib/shadcn/ui/breadcrumb.rb +180 -0
- data/lib/shadcn/ui/button.rb +63 -0
- data/lib/shadcn/ui/button_group.rb +58 -0
- data/lib/shadcn/ui/card.rb +133 -0
- data/lib/shadcn/ui/checkbox.rb +72 -0
- data/lib/shadcn/ui/collapsible.rb +76 -0
- data/lib/shadcn/ui/combobox.rb +229 -0
- data/lib/shadcn/ui/command.rb +256 -0
- data/lib/shadcn/ui/context_menu.rb +319 -0
- data/lib/shadcn/ui/dialog.rb +226 -0
- data/lib/shadcn/ui/direction.rb +23 -0
- data/lib/shadcn/ui/drawer.rb +217 -0
- data/lib/shadcn/ui/dropdown_menu.rb +384 -0
- data/lib/shadcn/ui/empty.rb +97 -0
- data/lib/shadcn/ui/field.rb +126 -0
- data/lib/shadcn/ui/hover_card.rb +75 -0
- data/lib/shadcn/ui/input.rb +36 -0
- data/lib/shadcn/ui/input_group.rb +32 -0
- data/lib/shadcn/ui/input_otp.rb +112 -0
- data/lib/shadcn/ui/item.rb +115 -0
- data/lib/shadcn/ui/kbd.rb +45 -0
- data/lib/shadcn/ui/label.rb +28 -0
- data/lib/shadcn/ui/menubar.rb +345 -0
- data/lib/shadcn/ui/native_select.rb +31 -0
- data/lib/shadcn/ui/navigation_menu.rb +238 -0
- data/lib/shadcn/ui/pagination.rb +224 -0
- data/lib/shadcn/ui/popover.rb +147 -0
- data/lib/shadcn/ui/progress.rb +40 -0
- data/lib/shadcn/ui/radio_group.rb +92 -0
- data/lib/shadcn/ui/resizable.rb +108 -0
- data/lib/shadcn/ui/scroll_area.rb +75 -0
- data/lib/shadcn/ui/select.rb +235 -0
- data/lib/shadcn/ui/separator.rb +36 -0
- data/lib/shadcn/ui/sheet.rb +231 -0
- data/lib/shadcn/ui/sidebar.rb +420 -0
- data/lib/shadcn/ui/skeleton.rb +23 -0
- data/lib/shadcn/ui/slider.rb +72 -0
- data/lib/shadcn/ui/sonner.rb +177 -0
- data/lib/shadcn/ui/spinner.rb +58 -0
- data/lib/shadcn/ui/switch.rb +75 -0
- data/lib/shadcn/ui/table.rb +154 -0
- data/lib/shadcn/ui/tabs.rb +154 -0
- data/lib/shadcn/ui/text_field.rb +146 -0
- data/lib/shadcn/ui/textarea.rb +32 -0
- data/lib/shadcn/ui/theme_toggle.rb +74 -0
- data/lib/shadcn/ui/toggle.rb +66 -0
- data/lib/shadcn/ui/toggle_group.rb +75 -0
- data/lib/shadcn/ui/tooltip.rb +78 -0
- data/lib/shadcn/ui/typography.rb +217 -0
- data/lib/shadcn/version.rb +5 -0
- data/lib/shadcn-phlex.rb +6 -0
- data/lib/shadcn.rb +80 -0
- data/package.json +14 -0
- data/skills/shadcn-phlex/SKILL.md +190 -0
- data/skills/shadcn-phlex/evals/evals.json +90 -0
- data/skills/shadcn-phlex/references/component-catalog.md +355 -0
- data/skills/shadcn-phlex/rules/composition.md +235 -0
- data/skills/shadcn-phlex/rules/forms.md +151 -0
- data/skills/shadcn-phlex/rules/helpers.md +54 -0
- data/skills/shadcn-phlex/rules/stimulus.md +61 -0
- data/skills/shadcn-phlex/rules/styling.md +177 -0
- metadata +209 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module UI
|
|
5
|
+
# Port of shadcn/ui ButtonGroup
|
|
6
|
+
class ButtonGroup < Base
|
|
7
|
+
def initialize(orientation: :horizontal, **attrs)
|
|
8
|
+
@orientation = orientation
|
|
9
|
+
@attrs = attrs
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def view_template(&block)
|
|
13
|
+
div(**build_attrs, &block)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def build_attrs
|
|
19
|
+
classes = cn(
|
|
20
|
+
"inline-flex items-center gap-0 -space-x-px shadow-xs",
|
|
21
|
+
"data-[orientation=vertical]:flex-col data-[orientation=vertical]:space-x-0 data-[orientation=vertical]:-space-y-px",
|
|
22
|
+
"[&_[data-slot=button]]:rounded-none [&_[data-slot=button]]:shadow-none",
|
|
23
|
+
"[&_[data-slot=button]:first-child]:rounded-s-md [&_[data-slot=button]:last-child]:rounded-e-md",
|
|
24
|
+
"data-[orientation=vertical]:[&_[data-slot=button]:first-child]:rounded-se-none data-[orientation=vertical]:[&_[data-slot=button]:first-child]:rounded-ss-md",
|
|
25
|
+
"data-[orientation=vertical]:[&_[data-slot=button]:last-child]:rounded-es-md data-[orientation=vertical]:[&_[data-slot=button]:last-child]:rounded-ee-none",
|
|
26
|
+
@attrs.delete(:class)
|
|
27
|
+
)
|
|
28
|
+
@attrs.merge(
|
|
29
|
+
data_slot: "button-group",
|
|
30
|
+
data_orientation: @orientation,
|
|
31
|
+
role: "group",
|
|
32
|
+
class: classes
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class ButtonGroupText < Base
|
|
38
|
+
def initialize(**attrs)
|
|
39
|
+
@attrs = attrs
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def view_template(&block)
|
|
43
|
+
span(**build_attrs, &block)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def build_attrs
|
|
49
|
+
classes = cn(
|
|
50
|
+
"inline-flex items-center justify-center border px-3 text-sm font-medium",
|
|
51
|
+
"border-input bg-background text-foreground",
|
|
52
|
+
@attrs.delete(:class)
|
|
53
|
+
)
|
|
54
|
+
@attrs.merge(data_slot: "button-group-text", class: classes)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module UI
|
|
5
|
+
# Port of shadcn/ui Card
|
|
6
|
+
# Sub-components: Card, CardHeader, CardTitle, CardDescription, CardAction, CardContent, CardFooter
|
|
7
|
+
class Card < Base
|
|
8
|
+
def initialize(**attrs)
|
|
9
|
+
@attrs = attrs
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def view_template(&block)
|
|
13
|
+
div(**build_attrs, &block)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def build_attrs
|
|
19
|
+
classes = cn(
|
|
20
|
+
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
|
|
21
|
+
@attrs.delete(:class)
|
|
22
|
+
)
|
|
23
|
+
@attrs.merge(data_slot: "card", class: classes)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
class CardHeader < Base
|
|
28
|
+
def initialize(**attrs)
|
|
29
|
+
@attrs = attrs
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def view_template(&block)
|
|
33
|
+
div(**build_attrs, &block)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def build_attrs
|
|
39
|
+
classes = cn(
|
|
40
|
+
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6",
|
|
41
|
+
"has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
|
|
42
|
+
@attrs.delete(:class)
|
|
43
|
+
)
|
|
44
|
+
@attrs.merge(data_slot: "card-header", class: classes)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
class CardTitle < Base
|
|
49
|
+
def initialize(**attrs)
|
|
50
|
+
@attrs = attrs
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def view_template(&block)
|
|
54
|
+
div(**build_attrs, &block)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def build_attrs
|
|
60
|
+
classes = cn("leading-none font-semibold", @attrs.delete(:class))
|
|
61
|
+
@attrs.merge(data_slot: "card-title", class: classes)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
class CardDescription < Base
|
|
66
|
+
def initialize(**attrs)
|
|
67
|
+
@attrs = attrs
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def view_template(&block)
|
|
71
|
+
div(**build_attrs, &block)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
def build_attrs
|
|
77
|
+
classes = cn("text-muted-foreground text-sm", @attrs.delete(:class))
|
|
78
|
+
@attrs.merge(data_slot: "card-description", class: classes)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
class CardAction < Base
|
|
83
|
+
def initialize(**attrs)
|
|
84
|
+
@attrs = attrs
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def view_template(&block)
|
|
88
|
+
div(**build_attrs, &block)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
def build_attrs
|
|
94
|
+
classes = cn("col-start-2 row-span-2 row-start-1 self-start justify-self-end", @attrs.delete(:class))
|
|
95
|
+
@attrs.merge(data_slot: "card-action", class: classes)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
class CardContent < Base
|
|
100
|
+
def initialize(**attrs)
|
|
101
|
+
@attrs = attrs
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def view_template(&block)
|
|
105
|
+
div(**build_attrs, &block)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
|
|
110
|
+
def build_attrs
|
|
111
|
+
classes = cn("px-6", @attrs.delete(:class))
|
|
112
|
+
@attrs.merge(data_slot: "card-content", class: classes)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
class CardFooter < Base
|
|
117
|
+
def initialize(**attrs)
|
|
118
|
+
@attrs = attrs
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def view_template(&block)
|
|
122
|
+
div(**build_attrs, &block)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
private
|
|
126
|
+
|
|
127
|
+
def build_attrs
|
|
128
|
+
classes = cn("flex items-center px-6 [.border-t]:pt-6", @attrs.delete(:class))
|
|
129
|
+
@attrs.merge(data_slot: "card-footer", class: classes)
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module UI
|
|
5
|
+
# Port of shadcn/ui Checkbox
|
|
6
|
+
class Checkbox < Base
|
|
7
|
+
def initialize(checked: false, name: nil, **attrs)
|
|
8
|
+
@checked = checked
|
|
9
|
+
@name = name
|
|
10
|
+
@attrs = attrs
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def view_template(&block)
|
|
14
|
+
label(data_controller: "shadcn--checkbox", data_shadcn__checkbox_checked_value: @checked.to_s, class: "inline-flex items-center gap-2 cursor-pointer") do
|
|
15
|
+
if @name
|
|
16
|
+
input(type: "hidden", name: @name, value: @checked ? "1" : "0", data_shadcn__checkbox_target: "input")
|
|
17
|
+
end
|
|
18
|
+
button(**build_attrs) do
|
|
19
|
+
span(
|
|
20
|
+
data_slot: "checkbox-indicator",
|
|
21
|
+
data_shadcn__checkbox_target: "indicator",
|
|
22
|
+
hidden: !@checked,
|
|
23
|
+
class: "grid place-content-center text-current transition-none"
|
|
24
|
+
) do
|
|
25
|
+
svg(
|
|
26
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
27
|
+
width: "14", height: "14",
|
|
28
|
+
viewbox: "0 0 24 24",
|
|
29
|
+
fill: "none",
|
|
30
|
+
stroke: "currentColor",
|
|
31
|
+
stroke_width: "2",
|
|
32
|
+
stroke_linecap: "round",
|
|
33
|
+
stroke_linejoin: "round",
|
|
34
|
+
class: "size-3.5"
|
|
35
|
+
) do |s|
|
|
36
|
+
s.path(d: "M20 6 9 17l-5-5")
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
if block
|
|
41
|
+
span(data_slot: "checkbox-label", class: "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", &block)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def build_attrs
|
|
49
|
+
classes = cn(
|
|
50
|
+
"peer size-4 shrink-0 rounded-[4px] border border-input shadow-xs",
|
|
51
|
+
"transition-shadow outline-none",
|
|
52
|
+
"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
|
|
53
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
54
|
+
"aria-invalid:border-destructive aria-invalid:ring-destructive/20",
|
|
55
|
+
"data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
|
56
|
+
"dark:bg-input/30 dark:aria-invalid:ring-destructive/40 dark:data-[state=checked]:bg-primary",
|
|
57
|
+
@attrs.delete(:class)
|
|
58
|
+
)
|
|
59
|
+
@attrs.merge(
|
|
60
|
+
data_slot: "checkbox",
|
|
61
|
+
data_shadcn__checkbox_target: "button",
|
|
62
|
+
data_action: "click->shadcn--checkbox#toggle",
|
|
63
|
+
data_state: @checked ? "checked" : "unchecked",
|
|
64
|
+
role: "checkbox",
|
|
65
|
+
type: "button",
|
|
66
|
+
aria_checked: @checked,
|
|
67
|
+
class: classes
|
|
68
|
+
)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module UI
|
|
5
|
+
# Port of shadcn/ui Collapsible
|
|
6
|
+
# Uses data-state="open"/"closed" for JS interactivity
|
|
7
|
+
class Collapsible < Base
|
|
8
|
+
def initialize(open: false, **attrs)
|
|
9
|
+
@open = open
|
|
10
|
+
@attrs = attrs
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def view_template(&block)
|
|
14
|
+
div(**build_attrs, &block)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def build_attrs
|
|
20
|
+
@attrs.merge(
|
|
21
|
+
data_slot: "collapsible",
|
|
22
|
+
data_state: @open ? "open" : "closed",
|
|
23
|
+
data_controller: "shadcn--collapsible",
|
|
24
|
+
data_shadcn__collapsible_open_value: @open
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class CollapsibleTrigger < Base
|
|
30
|
+
def initialize(**attrs)
|
|
31
|
+
@attrs = attrs
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def view_template(&block)
|
|
35
|
+
div(**build_attrs, &block)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def build_attrs
|
|
41
|
+
@attrs.merge(
|
|
42
|
+
data_slot: "collapsible-trigger",
|
|
43
|
+
data_shadcn__collapsible_target: "trigger",
|
|
44
|
+
data_action: "click->shadcn--collapsible#toggle",
|
|
45
|
+
role: "button",
|
|
46
|
+
style: "display: inline-block"
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
class CollapsibleContent < Base
|
|
52
|
+
def initialize(**attrs)
|
|
53
|
+
@attrs = attrs
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def view_template(&block)
|
|
57
|
+
div(**build_attrs, &block)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def build_attrs
|
|
63
|
+
classes = cn(
|
|
64
|
+
"overflow-hidden",
|
|
65
|
+
"data-[state=closed]:animate-collapsible-up data-[state=open]:animate-collapsible-down",
|
|
66
|
+
@attrs.delete(:class)
|
|
67
|
+
)
|
|
68
|
+
@attrs.merge(
|
|
69
|
+
data_slot: "collapsible-content",
|
|
70
|
+
data_shadcn__collapsible_target: "content",
|
|
71
|
+
class: classes
|
|
72
|
+
)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module UI
|
|
5
|
+
# Port of shadcn/ui Combobox
|
|
6
|
+
# Searchable select with filtering
|
|
7
|
+
# Wired to shadcn--combobox Stimulus controller
|
|
8
|
+
class Combobox < Base
|
|
9
|
+
def initialize(name: nil, **attrs)
|
|
10
|
+
@name = name
|
|
11
|
+
@attrs = attrs
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def view_template(&block)
|
|
15
|
+
div(**build_attrs) do
|
|
16
|
+
if @name
|
|
17
|
+
input(type: "hidden", name: @name, value: "", data_shadcn__combobox_target: "hiddenInput")
|
|
18
|
+
end
|
|
19
|
+
yield if block_given?
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def build_attrs
|
|
26
|
+
classes = cn("relative", @attrs.delete(:class))
|
|
27
|
+
@attrs.merge(
|
|
28
|
+
data_slot: "combobox",
|
|
29
|
+
data_controller: "shadcn--combobox",
|
|
30
|
+
data_action: "click@window->shadcn--combobox#hide keydown.esc@window->shadcn--combobox#hideOnEscape keydown->shadcn--combobox#keydown",
|
|
31
|
+
class: classes
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class ComboboxTrigger < Base
|
|
37
|
+
def initialize(**attrs)
|
|
38
|
+
@attrs = attrs
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def view_template(&block)
|
|
42
|
+
button(**build_attrs) do
|
|
43
|
+
yield if block_given?
|
|
44
|
+
# ChevronsUpDown icon
|
|
45
|
+
svg(xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16",
|
|
46
|
+
viewbox: "0 0 24 24", fill: "none", stroke: "currentColor",
|
|
47
|
+
stroke_width: "2", class: "ml-2 size-4 shrink-0 opacity-50") do |s|
|
|
48
|
+
s.path(d: "m7 15 5 5 5-5")
|
|
49
|
+
s.path(d: "m7 9 5-5 5 5")
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def build_attrs
|
|
57
|
+
classes = cn(
|
|
58
|
+
"flex h-9 w-full items-center justify-between gap-2 rounded-md border border-input bg-transparent px-3",
|
|
59
|
+
"text-sm shadow-xs transition-[color,box-shadow] outline-none whitespace-nowrap",
|
|
60
|
+
"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
|
|
61
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
62
|
+
"dark:bg-input/30",
|
|
63
|
+
"[&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
64
|
+
@attrs.delete(:class)
|
|
65
|
+
)
|
|
66
|
+
@attrs.merge(
|
|
67
|
+
data_slot: "combobox-trigger",
|
|
68
|
+
data_action: "click->shadcn--combobox#toggle",
|
|
69
|
+
type: "button",
|
|
70
|
+
role: "combobox",
|
|
71
|
+
class: classes
|
|
72
|
+
)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
class ComboboxValue < Base
|
|
77
|
+
def initialize(placeholder: "Select...", **attrs)
|
|
78
|
+
@placeholder = placeholder
|
|
79
|
+
@attrs = attrs
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def view_template(&block)
|
|
83
|
+
span(**build_attrs) do
|
|
84
|
+
if block_given?
|
|
85
|
+
yield
|
|
86
|
+
else
|
|
87
|
+
plain @placeholder
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
private
|
|
93
|
+
|
|
94
|
+
def build_attrs
|
|
95
|
+
@attrs.merge(
|
|
96
|
+
data_slot: "combobox-value",
|
|
97
|
+
data_shadcn__combobox_target: "value"
|
|
98
|
+
)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
class ComboboxContent < Base
|
|
103
|
+
def initialize(**attrs)
|
|
104
|
+
@attrs = attrs
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def view_template(&block)
|
|
108
|
+
div(**build_attrs, &block)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
private
|
|
112
|
+
|
|
113
|
+
def build_attrs
|
|
114
|
+
classes = cn(
|
|
115
|
+
"z-50 w-full min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
|
|
116
|
+
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
|
|
117
|
+
"data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
|
|
118
|
+
@attrs.delete(:class)
|
|
119
|
+
)
|
|
120
|
+
@attrs.merge(
|
|
121
|
+
data_slot: "combobox-content",
|
|
122
|
+
data_shadcn__combobox_target: "content",
|
|
123
|
+
role: "listbox",
|
|
124
|
+
hidden: true,
|
|
125
|
+
class: classes
|
|
126
|
+
)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
class ComboboxInput < Base
|
|
131
|
+
def initialize(placeholder: "Search...", **attrs)
|
|
132
|
+
@placeholder = placeholder
|
|
133
|
+
@attrs = attrs
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def view_template
|
|
137
|
+
div(class: "flex items-center border-b px-3") do
|
|
138
|
+
svg(xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16",
|
|
139
|
+
viewbox: "0 0 24 24", fill: "none", stroke: "currentColor",
|
|
140
|
+
stroke_width: "2", class: "mr-2 size-4 shrink-0 opacity-50") do |s|
|
|
141
|
+
s.circle(cx: "11", cy: "11", r: "8")
|
|
142
|
+
s.path(d: "m21 21-4.3-4.3")
|
|
143
|
+
end
|
|
144
|
+
input(**build_attrs)
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
private
|
|
149
|
+
|
|
150
|
+
def build_attrs
|
|
151
|
+
classes = cn(
|
|
152
|
+
"flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none",
|
|
153
|
+
"placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
|
154
|
+
@attrs.delete(:class)
|
|
155
|
+
)
|
|
156
|
+
@attrs.merge(
|
|
157
|
+
data_slot: "combobox-input",
|
|
158
|
+
data_shadcn__combobox_target: "input",
|
|
159
|
+
data_action: "input->shadcn--combobox#filter keydown->shadcn--combobox#keydown",
|
|
160
|
+
type: "text",
|
|
161
|
+
placeholder: @placeholder,
|
|
162
|
+
class: classes
|
|
163
|
+
)
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
class ComboboxEmpty < Base
|
|
168
|
+
def initialize(**attrs)
|
|
169
|
+
@attrs = attrs
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def view_template(&block)
|
|
173
|
+
div(**build_attrs) do
|
|
174
|
+
if block_given?
|
|
175
|
+
yield
|
|
176
|
+
else
|
|
177
|
+
plain "No results found."
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
private
|
|
183
|
+
|
|
184
|
+
def build_attrs
|
|
185
|
+
classes = cn("py-6 text-center text-sm text-muted-foreground", @attrs.delete(:class))
|
|
186
|
+
@attrs.merge(
|
|
187
|
+
data_slot: "combobox-empty",
|
|
188
|
+
data_shadcn__combobox_target: "empty",
|
|
189
|
+
hidden: true,
|
|
190
|
+
class: classes
|
|
191
|
+
)
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
class ComboboxItem < Base
|
|
196
|
+
def initialize(value:, **attrs)
|
|
197
|
+
@value = value
|
|
198
|
+
@attrs = attrs
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def view_template(&block)
|
|
202
|
+
div(**build_attrs, &block)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
private
|
|
206
|
+
|
|
207
|
+
def build_attrs
|
|
208
|
+
classes = cn(
|
|
209
|
+
"relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm",
|
|
210
|
+
"outline-hidden select-none",
|
|
211
|
+
"data-[state=checked]:font-medium",
|
|
212
|
+
"focus:bg-accent focus:text-accent-foreground",
|
|
213
|
+
"hover:bg-accent hover:text-accent-foreground",
|
|
214
|
+
"data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
215
|
+
@attrs.delete(:class)
|
|
216
|
+
)
|
|
217
|
+
@attrs.merge(
|
|
218
|
+
data_slot: "combobox-item",
|
|
219
|
+
data_shadcn__combobox_target: "item",
|
|
220
|
+
data_action: "click->shadcn--combobox#selectItem",
|
|
221
|
+
data_value: @value,
|
|
222
|
+
role: "option",
|
|
223
|
+
tabindex: "-1",
|
|
224
|
+
class: classes
|
|
225
|
+
)
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|