ruby_ui 1.0.0 → 1.0.2
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/README.md +5 -0
- data/lib/generators/ruby_ui/component/all_generator.rb +22 -0
- data/lib/generators/ruby_ui/component_generator.rb +4 -3
- data/lib/generators/ruby_ui/install/install_generator.rb +1 -7
- data/lib/generators/ruby_ui/install/templates/tailwind.css.erb +0 -3
- data/lib/generators/ruby_ui/javascript_utils.rb +4 -0
- data/lib/ruby_ui/alert_dialog/alert_dialog_content.rb +2 -3
- data/lib/ruby_ui/button/button.rb +32 -16
- data/lib/ruby_ui/checkbox/checkbox.rb +7 -1
- data/lib/ruby_ui/combobox/combobox.rb +3 -2
- data/lib/ruby_ui/combobox/combobox_checkbox.rb +4 -2
- data/lib/ruby_ui/combobox/combobox_controller.js +4 -4
- data/lib/ruby_ui/combobox/combobox_item.rb +2 -1
- data/lib/ruby_ui/combobox/combobox_radio.rb +8 -1
- data/lib/ruby_ui/combobox/combobox_search_input.rb +11 -5
- data/lib/ruby_ui/combobox/combobox_toggle_all_checkbox.rb +2 -1
- data/lib/ruby_ui/combobox/combobox_trigger.rb +7 -1
- data/lib/ruby_ui/command/command_controller.js +0 -1
- data/lib/ruby_ui/dialog/dialog_content.rb +2 -3
- data/lib/ruby_ui/dialog/dialog_controller.js +1 -1
- data/lib/ruby_ui/dropdown_menu/dropdown_menu.rb +9 -0
- data/lib/ruby_ui/dropdown_menu/dropdown_menu_content.rb +17 -2
- data/lib/ruby_ui/dropdown_menu/dropdown_menu_controller.js +43 -14
- data/lib/ruby_ui/form/form_field_label.rb +7 -1
- data/lib/ruby_ui/input/input.rb +8 -1
- data/lib/ruby_ui/link/link.rb +32 -16
- data/lib/ruby_ui/radio_button/radio_button.rb +3 -1
- data/lib/ruby_ui/select/select_item.rb +14 -5
- data/lib/ruby_ui/select/select_trigger.rb +9 -4
- data/lib/ruby_ui/sidebar/collapsible_sidebar.rb +99 -0
- data/lib/ruby_ui/sidebar/mobile_sidebar.rb +45 -0
- data/lib/ruby_ui/sidebar/non_collapsible_sidebar.rb +17 -0
- data/lib/ruby_ui/sidebar/sidebar.rb +29 -0
- data/lib/ruby_ui/sidebar/sidebar_content.rb +20 -0
- data/lib/ruby_ui/sidebar/sidebar_controller.js +67 -0
- data/lib/ruby_ui/sidebar/sidebar_footer.rb +20 -0
- data/lib/ruby_ui/sidebar/sidebar_group.rb +20 -0
- data/lib/ruby_ui/sidebar/sidebar_group_action.rb +33 -0
- data/lib/ruby_ui/sidebar/sidebar_group_content.rb +20 -0
- data/lib/ruby_ui/sidebar/sidebar_group_label.rb +26 -0
- data/lib/ruby_ui/sidebar/sidebar_header.rb +20 -0
- data/lib/ruby_ui/sidebar/sidebar_input.rb +20 -0
- data/lib/ruby_ui/sidebar/sidebar_inset.rb +23 -0
- data/lib/ruby_ui/sidebar/sidebar_menu.rb +20 -0
- data/lib/ruby_ui/sidebar/sidebar_menu_action.rb +48 -0
- data/lib/ruby_ui/sidebar/sidebar_menu_badge.rb +30 -0
- data/lib/ruby_ui/sidebar/sidebar_menu_button.rb +63 -0
- data/lib/ruby_ui/sidebar/sidebar_menu_item.rb +20 -0
- data/lib/ruby_ui/sidebar/sidebar_menu_skeleton.rb +36 -0
- data/lib/ruby_ui/sidebar/sidebar_menu_sub.rb +24 -0
- data/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb +50 -0
- data/lib/ruby_ui/sidebar/sidebar_menu_sub_item.rb +9 -0
- data/lib/ruby_ui/sidebar/sidebar_rail.rb +36 -0
- data/lib/ruby_ui/sidebar/sidebar_separator.rb +20 -0
- data/lib/ruby_ui/sidebar/sidebar_trigger.rb +42 -0
- data/lib/ruby_ui/sidebar/sidebar_wrapper.rb +24 -0
- data/lib/ruby_ui/switch/switch.rb +12 -2
- data/lib/ruby_ui/table/table_footer.rb +1 -1
- data/lib/ruby_ui/table/table_row.rb +1 -1
- data/lib/ruby_ui/tabs/tabs_trigger.rb +7 -1
- data/lib/ruby_ui/textarea/textarea.rb +8 -1
- data/lib/ruby_ui/theme_toggle/set_dark_mode.rb +16 -0
- data/lib/ruby_ui/theme_toggle/set_light_mode.rb +16 -0
- data/lib/ruby_ui/theme_toggle/theme_toggle.rb +0 -32
- data/lib/ruby_ui/tooltip/tooltip_controller.js +5 -4
- data/lib/ruby_ui.rb +1 -1
- metadata +34 -4
data/lib/ruby_ui/input/input.rb
CHANGED
@@ -19,7 +19,14 @@ module RubyUI
|
|
19
19
|
ruby_ui__form_field_target: "input",
|
20
20
|
action: "input->ruby-ui--form-field#onInput invalid->ruby-ui--form-field#onInvalid"
|
21
21
|
},
|
22
|
-
class:
|
22
|
+
class: [
|
23
|
+
"flex h-9 w-full rounded-md border bg-background px-3 py-1 text-sm shadow-sm transition-colors border-border",
|
24
|
+
"placeholder:text-muted-foreground",
|
25
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
26
|
+
"file:border-0 file:bg-transparent file:text-sm file:font-medium",
|
27
|
+
"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
28
|
+
"aria-disabled:cursor-not-allowed aria-disabled:opacity-50 aria-disabled:pointer-events-none"
|
29
|
+
]
|
23
30
|
}
|
24
31
|
end
|
25
32
|
end
|
data/lib/ruby_ui/link/link.rb
CHANGED
@@ -2,6 +2,13 @@
|
|
2
2
|
|
3
3
|
module RubyUI
|
4
4
|
class Link < Base
|
5
|
+
BASE_CLASSES = [
|
6
|
+
"whitespace-nowrap inline-flex items-center justify-center rounded-md font-medium transition-colors",
|
7
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
8
|
+
"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
9
|
+
"aria-disabled:pointer-events-none aria-disabled:opacity-50 aria-disabled:cursor-not-allowed"
|
10
|
+
].freeze
|
11
|
+
|
5
12
|
def initialize(href: "#", variant: :link, size: :md, icon: false, **attrs)
|
6
13
|
@href = href
|
7
14
|
@variant = variant.to_sym
|
@@ -36,43 +43,55 @@ module RubyUI
|
|
36
43
|
|
37
44
|
def primary_classes
|
38
45
|
[
|
39
|
-
|
40
|
-
size_classes
|
46
|
+
BASE_CLASSES,
|
47
|
+
size_classes,
|
48
|
+
"bg-primary text-primary-foreground shadow",
|
49
|
+
"hover:bg-primary/90"
|
41
50
|
]
|
42
51
|
end
|
43
52
|
|
44
53
|
def link_classes
|
45
54
|
[
|
46
|
-
|
47
|
-
size_classes
|
55
|
+
BASE_CLASSES,
|
56
|
+
size_classes,
|
57
|
+
"text-primary underline-offset-4",
|
58
|
+
"hover:underline"
|
48
59
|
]
|
49
60
|
end
|
50
61
|
|
51
62
|
def secondary_classes
|
52
63
|
[
|
53
|
-
|
54
|
-
size_classes
|
64
|
+
BASE_CLASSES,
|
65
|
+
size_classes,
|
66
|
+
"bg-secondary text-secondary-foreground",
|
67
|
+
"hover:bg-opacity-80"
|
55
68
|
]
|
56
69
|
end
|
57
70
|
|
58
71
|
def destructive_classes
|
59
72
|
[
|
60
|
-
|
61
|
-
size_classes
|
73
|
+
BASE_CLASSES,
|
74
|
+
size_classes,
|
75
|
+
"bg-destructive text-white shadow-sm",
|
76
|
+
"[a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20",
|
77
|
+
"dark:focus-visible:ring-destructive/40 dark:bg-destructive/60"
|
62
78
|
]
|
63
79
|
end
|
64
80
|
|
65
81
|
def outline_classes
|
66
82
|
[
|
67
|
-
|
68
|
-
size_classes
|
83
|
+
BASE_CLASSES,
|
84
|
+
size_classes,
|
85
|
+
"border border-input bg-background shadow-sm",
|
86
|
+
"hover:bg-accent hover:text-accent-foreground"
|
69
87
|
]
|
70
88
|
end
|
71
89
|
|
72
90
|
def ghost_classes
|
73
91
|
[
|
74
|
-
|
75
|
-
size_classes
|
92
|
+
BASE_CLASSES,
|
93
|
+
size_classes,
|
94
|
+
"hover:bg-accent hover:text-accent-foreground"
|
76
95
|
]
|
77
96
|
end
|
78
97
|
|
@@ -88,10 +107,7 @@ module RubyUI
|
|
88
107
|
end
|
89
108
|
|
90
109
|
def default_attrs
|
91
|
-
{
|
92
|
-
type: "button",
|
93
|
-
class: default_classes
|
94
|
-
}
|
110
|
+
{type: "button", class: default_classes}
|
95
111
|
end
|
96
112
|
end
|
97
113
|
end
|
@@ -17,7 +17,9 @@ module RubyUI
|
|
17
17
|
},
|
18
18
|
class: [
|
19
19
|
"h-4 w-4 p-0 border-primary rounded-full flex-none",
|
20
|
-
"disabled:cursor-not-allowed disabled:opacity-50"
|
20
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
21
|
+
"checked:bg-primary checked:text-primary-foreground",
|
22
|
+
"aria-disabled:cursor-not-allowed aria-disabled:opacity-50 aria-disabled:pointer-events-none"
|
21
23
|
]
|
22
24
|
}
|
23
25
|
end
|
@@ -37,15 +37,24 @@ module RubyUI
|
|
37
37
|
{
|
38
38
|
role: "option",
|
39
39
|
tabindex: "0",
|
40
|
-
|
40
|
+
data_value: @value,
|
41
|
+
aria_selected: "false",
|
42
|
+
data_orientation: "vertical",
|
43
|
+
class: [
|
44
|
+
"item group relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors",
|
45
|
+
"focus:bg-accent focus:text-accent-foreground",
|
46
|
+
"hover:bg-accent hover:text-accent-foreground",
|
47
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
48
|
+
"aria-selected:bg-accent aria-selected:text-accent-foreground",
|
49
|
+
"data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
50
|
+
"aria-disabled:pointer-events-none aria-disabled:opacity-50 aria-disabled:cursor-not-allowed"
|
51
|
+
],
|
41
52
|
data: {
|
42
53
|
controller: "ruby-ui--select-item",
|
43
54
|
action: "click->ruby-ui--select#selectItem keydown.enter->ruby-ui--select#selectItem keydown.down->ruby-ui--select#handleKeyDown keydown.up->ruby-ui--select#handleKeyUp keydown.esc->ruby-ui--select#handleEsc",
|
44
55
|
ruby_ui__select_target: "item"
|
45
|
-
}
|
46
|
-
|
47
|
-
data_orientation: "vertical",
|
48
|
-
aria_selected: "false"
|
56
|
+
}
|
57
|
+
|
49
58
|
}
|
50
59
|
end
|
51
60
|
end
|
@@ -33,12 +33,12 @@ module RubyUI
|
|
33
33
|
|
34
34
|
def default_attrs
|
35
35
|
{
|
36
|
+
type: "button",
|
37
|
+
role: "combobox",
|
36
38
|
data: {
|
37
39
|
action: "ruby-ui--select#onClick",
|
38
40
|
ruby_ui__select_target: "trigger"
|
39
41
|
},
|
40
|
-
type: "button",
|
41
|
-
role: "combobox",
|
42
42
|
aria: {
|
43
43
|
controls: "radix-:r0:",
|
44
44
|
expanded: "false",
|
@@ -46,8 +46,13 @@ module RubyUI
|
|
46
46
|
haspopup: "listbox",
|
47
47
|
activedescendant: true
|
48
48
|
},
|
49
|
-
class:
|
50
|
-
"truncate w-full flex h-9 items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background
|
49
|
+
class: [
|
50
|
+
"truncate w-full flex h-9 items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background",
|
51
|
+
"placeholder:text-muted-foreground",
|
52
|
+
"focus:outline-none focus:ring-1 focus:ring-ring",
|
53
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
54
|
+
"aria-disabled:cursor-not-allowed aria-disabled:opacity-50 aria-disabled:pointer-events-none"
|
55
|
+
]
|
51
56
|
}
|
52
57
|
end
|
53
58
|
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyUI
|
4
|
+
class CollapsibleSidebar < Base
|
5
|
+
def initialize(side: :left, variant: :sidebar, collapsible: :offcanvas, open: true, **attrs)
|
6
|
+
@side = side
|
7
|
+
@variant = variant
|
8
|
+
@collapsible = collapsible
|
9
|
+
@open = open
|
10
|
+
super(**attrs)
|
11
|
+
end
|
12
|
+
|
13
|
+
def view_template(&)
|
14
|
+
MobileSidebar(side: @side, **attrs, &)
|
15
|
+
div(**mix(sidebar_attrs, attrs)) do
|
16
|
+
div(**gap_element_attrs)
|
17
|
+
div(**content_wrapper_attrs) do
|
18
|
+
div(**content_attrs, &)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def sidebar_attrs
|
26
|
+
{
|
27
|
+
class: "group peer hidden text-sidebar-foreground md:block",
|
28
|
+
data: {
|
29
|
+
state: @open ? "expanded" : "collapsed",
|
30
|
+
collapsible: @open ? "" : @collapsible,
|
31
|
+
variant: @variant,
|
32
|
+
side: @side,
|
33
|
+
collapsible_kind: @collapsible,
|
34
|
+
ruby_ui__sidebar_target: "sidebar"
|
35
|
+
}
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
def gap_element_attrs
|
40
|
+
{
|
41
|
+
class: [
|
42
|
+
"relative w-[var(--sidebar-width)] bg-transparent transition-[width]",
|
43
|
+
"duration-200 ease-linear",
|
44
|
+
"group-data-[collapsible=offcanvas]:w-0",
|
45
|
+
"group-data-[side=right]:rotate-180",
|
46
|
+
variant_classes
|
47
|
+
]
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
def content_wrapper_attrs
|
52
|
+
{
|
53
|
+
class: [
|
54
|
+
"fixed inset-y-0 z-10 hidden h-svh w-[var(--sidebar-width)]",
|
55
|
+
"transition-[left,right,width] duration-200 ease-linear md:flex",
|
56
|
+
content_wrapper_side_classes,
|
57
|
+
content_wrapper_variant_classes
|
58
|
+
]
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
def content_attrs
|
63
|
+
{
|
64
|
+
class: [
|
65
|
+
"flex h-full w-full flex-col bg-sidebar",
|
66
|
+
"group-data-[variant=floating]:rounded-lg",
|
67
|
+
"group-data-[variant=floating]:border",
|
68
|
+
"group-data-[variant=floating]:border-sidebar-border",
|
69
|
+
"group-data-[variant=floating]:shadow"
|
70
|
+
],
|
71
|
+
data: {
|
72
|
+
sidebar: "sidebar"
|
73
|
+
}
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
def variant_classes
|
78
|
+
if %i[floating inset].include?(@variant)
|
79
|
+
"group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]"
|
80
|
+
else
|
81
|
+
"group-data-[collapsible=icon]:w-[var(--sidebar-width-icon)]"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def content_wrapper_side_classes
|
86
|
+
return "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]" if @side == :left
|
87
|
+
|
88
|
+
"right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]"
|
89
|
+
end
|
90
|
+
|
91
|
+
def content_wrapper_variant_classes
|
92
|
+
if %i[floating inset].include?(@variant)
|
93
|
+
"p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]"
|
94
|
+
else
|
95
|
+
"group-data-[collapsible=icon]:w-[var(--sidebar-width-icon)] group-data-[side=left]:border-r group-data-[side=right]:border-l"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyUI
|
4
|
+
class MobileSidebar < Base
|
5
|
+
SIDEBAR_WIDTH_MOBILE = "18rem"
|
6
|
+
|
7
|
+
def initialize(side: :left, **attrs)
|
8
|
+
@side = side
|
9
|
+
super(**attrs)
|
10
|
+
end
|
11
|
+
|
12
|
+
def view_template(&)
|
13
|
+
Sheet(**attrs) do
|
14
|
+
SheetContent(
|
15
|
+
side: @side,
|
16
|
+
class: "w-[var(--sidebar-width)] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden",
|
17
|
+
style: {
|
18
|
+
"--sidebar-width": SIDEBAR_WIDTH_MOBILE
|
19
|
+
},
|
20
|
+
data: {
|
21
|
+
sidebar: "sidebar",
|
22
|
+
mobile: "true"
|
23
|
+
}
|
24
|
+
) do
|
25
|
+
SheetHeader(class: "sr-only") do
|
26
|
+
SheetTitle { "Sidebar" }
|
27
|
+
SheetDescription { "Displays the mobile sidebar." }
|
28
|
+
end
|
29
|
+
div(class: "flex h-full w-full flex-col", &)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def default_attrs
|
37
|
+
{
|
38
|
+
data: {
|
39
|
+
ruby_ui__sidebar_target: "mobileSidebar",
|
40
|
+
action: "ruby--ui-sidebar:open->ruby-ui--sheet#open:self"
|
41
|
+
}
|
42
|
+
}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyUI
|
4
|
+
class NonCollapsibleSidebar < Base
|
5
|
+
def view_template(&)
|
6
|
+
div(**attrs, &)
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def default_attrs
|
12
|
+
{
|
13
|
+
class: "flex h-full w-[var(--sidebar-width)] flex-col bg-sidebar text-sidebar-foreground"
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyUI
|
4
|
+
class Sidebar < Base
|
5
|
+
SIDES = %i[left right].freeze
|
6
|
+
VARIANTS = %i[sidebar floating inset].freeze
|
7
|
+
COLLAPSIBLES = %i[offcanvas icon none].freeze
|
8
|
+
|
9
|
+
def initialize(side: :left, variant: :sidebar, collapsible: :offcanvas, open: true, **attrs)
|
10
|
+
raise ArgumentError, "Invalid side: #{side}." unless SIDES.include?(side.to_sym)
|
11
|
+
raise ArgumentError "Invalid variant: #{variant}." unless VARIANTS.include?(variant.to_sym)
|
12
|
+
raise ArgumentError, "Invalid collapsible: #{collapsible}." unless COLLAPSIBLES.include?(collapsible.to_sym)
|
13
|
+
|
14
|
+
@side = side.to_sym
|
15
|
+
@variant = variant.to_sym
|
16
|
+
@collapsible = collapsible.to_sym
|
17
|
+
@open = open
|
18
|
+
super(**attrs)
|
19
|
+
end
|
20
|
+
|
21
|
+
def view_template(&)
|
22
|
+
if @collapsible == :none
|
23
|
+
NonCollapsibleSidebar(**attrs, &)
|
24
|
+
else
|
25
|
+
CollapsibleSidebar(side: @side, variant: @variant, collapsible: @collapsible, open: @open, **attrs, &)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyUI
|
4
|
+
class SidebarContent < Base
|
5
|
+
def view_template(&)
|
6
|
+
div(**attrs, &)
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def default_attrs
|
12
|
+
{
|
13
|
+
class: "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
|
14
|
+
data: {
|
15
|
+
sidebar: "content"
|
16
|
+
}
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus";
|
2
|
+
|
3
|
+
const SIDEBAR_COOKIE_NAME = "sidebar_state";
|
4
|
+
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
|
5
|
+
const State = {
|
6
|
+
EXPANDED: "expanded",
|
7
|
+
COLLAPSED: "collapsed",
|
8
|
+
};
|
9
|
+
const MOBILE_BREAKPOINT = 768;
|
10
|
+
|
11
|
+
export default class extends Controller {
|
12
|
+
static targets = ["sidebar", "mobileSidebar"];
|
13
|
+
|
14
|
+
sidebarTargetConnected() {
|
15
|
+
const { state, collapsibleKind } = this.sidebarTarget.dataset;
|
16
|
+
|
17
|
+
this.open = state === State.EXPANDED;
|
18
|
+
this.collapsibleKind = collapsibleKind;
|
19
|
+
}
|
20
|
+
|
21
|
+
toggle(e) {
|
22
|
+
e.preventDefault();
|
23
|
+
|
24
|
+
if (this.#isMobile()) {
|
25
|
+
this.#openMobileSidebar();
|
26
|
+
|
27
|
+
return;
|
28
|
+
}
|
29
|
+
|
30
|
+
this.open = !this.open;
|
31
|
+
this.onToggle();
|
32
|
+
}
|
33
|
+
|
34
|
+
onToggle() {
|
35
|
+
this.#updateSidebarState();
|
36
|
+
this.#persistSidebarState();
|
37
|
+
}
|
38
|
+
|
39
|
+
#updateSidebarState() {
|
40
|
+
if (!this.hasSidebarTarget) {
|
41
|
+
return;
|
42
|
+
}
|
43
|
+
|
44
|
+
const { dataset } = this.sidebarTarget;
|
45
|
+
|
46
|
+
dataset.state = this.open ? State.EXPANDED : State.COLLAPSED;
|
47
|
+
dataset.collapsible = this.open ? "" : this.collapsibleKind;
|
48
|
+
}
|
49
|
+
|
50
|
+
#persistSidebarState() {
|
51
|
+
document.cookie = `${SIDEBAR_COOKIE_NAME}=${this.open}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
|
52
|
+
}
|
53
|
+
|
54
|
+
#isMobile() {
|
55
|
+
return window.innerWidth < MOBILE_BREAKPOINT;
|
56
|
+
}
|
57
|
+
|
58
|
+
#openMobileSidebar() {
|
59
|
+
if (!this.hasMobileSidebarTarget) {
|
60
|
+
return;
|
61
|
+
}
|
62
|
+
|
63
|
+
this.mobileSidebarTarget.dispatchEvent(
|
64
|
+
new CustomEvent("ruby--ui-sidebar:open"),
|
65
|
+
);
|
66
|
+
}
|
67
|
+
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyUI
|
4
|
+
class SidebarFooter < Base
|
5
|
+
def view_template(&)
|
6
|
+
div(**attrs, &)
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def default_attrs
|
12
|
+
{
|
13
|
+
class: "flex flex-col gap-2 p-2",
|
14
|
+
data: {
|
15
|
+
sidebar: "footer"
|
16
|
+
}
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyUI
|
4
|
+
class SidebarGroup < Base
|
5
|
+
def view_template(&)
|
6
|
+
div(**attrs, &)
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def default_attrs
|
12
|
+
{
|
13
|
+
class: "relative flex w-full min-w-0 flex-col p-2",
|
14
|
+
data: {
|
15
|
+
sidebar: "group"
|
16
|
+
}
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyUI
|
4
|
+
class SidebarGroupAction < Base
|
5
|
+
def initialize(as: :button, **attrs)
|
6
|
+
@as = as
|
7
|
+
super(**attrs)
|
8
|
+
end
|
9
|
+
|
10
|
+
def view_template(&)
|
11
|
+
tag(@as, **attrs, &)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def default_attrs
|
17
|
+
{
|
18
|
+
class: [
|
19
|
+
"absolute right-3 top-3.5 flex aspect-square w-5 items-center",
|
20
|
+
"justify-center rounded-md p-0 text-sidebar-foreground",
|
21
|
+
"outline-none ring-sidebar-ring transition-transform",
|
22
|
+
"hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
23
|
+
"focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
|
24
|
+
"after:absolute after:-inset-2 after:md:hidden",
|
25
|
+
"group-data-[collapsible=icon]:hidden"
|
26
|
+
],
|
27
|
+
data: {
|
28
|
+
sidebar: "group-action"
|
29
|
+
}
|
30
|
+
}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyUI
|
4
|
+
class SidebarGroupContent < Base
|
5
|
+
def view_template(&)
|
6
|
+
div(**attrs, &)
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def default_attrs
|
12
|
+
{
|
13
|
+
class: "w-full text-sm",
|
14
|
+
data: {
|
15
|
+
sidebar: "group-content"
|
16
|
+
}
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyUI
|
4
|
+
class SidebarGroupLabel < Base
|
5
|
+
def view_template(&)
|
6
|
+
div(**attrs, &)
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def default_attrs
|
12
|
+
{
|
13
|
+
class: [
|
14
|
+
"flex h-8 shrink-0 items-center rounded-md px-2 text-xs",
|
15
|
+
"font-medium text-sidebar-foreground/70 outline-none",
|
16
|
+
"ring-sidebar-ring transition-[margin,opacity] duration-200",
|
17
|
+
"ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
|
18
|
+
"group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0"
|
19
|
+
],
|
20
|
+
data: {
|
21
|
+
sidebar: "group-label"
|
22
|
+
}
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyUI
|
4
|
+
class SidebarHeader < Base
|
5
|
+
def view_template(&)
|
6
|
+
div(**attrs, &)
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def default_attrs
|
12
|
+
{
|
13
|
+
class: "flex flex-col gap-2 p-2",
|
14
|
+
data: {
|
15
|
+
sidebar: "header"
|
16
|
+
}
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyUI
|
4
|
+
class SidebarInput < Base
|
5
|
+
def view_template(&)
|
6
|
+
Input(**attrs, &)
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def default_attrs
|
12
|
+
{
|
13
|
+
class: "h-8 w-full bg-background shadow-none focus-visible:ring-2 focus-visible:ring-sidebar-ring",
|
14
|
+
data: {
|
15
|
+
sidebar: "input"
|
16
|
+
}
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyUI
|
4
|
+
class SidebarInset < Base
|
5
|
+
def view_template(&)
|
6
|
+
main(**attrs, &)
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def default_attrs
|
12
|
+
{
|
13
|
+
class: [
|
14
|
+
"relative flex w-full flex-1 flex-col bg-background",
|
15
|
+
"md:peer-data-[variant=inset]:m-2",
|
16
|
+
"md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2",
|
17
|
+
"md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl",
|
18
|
+
"md:peer-data-[variant=inset]:shadow"
|
19
|
+
]
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyUI
|
4
|
+
class SidebarMenu < Base
|
5
|
+
def view_template(&)
|
6
|
+
ul(**attrs, &)
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def default_attrs
|
12
|
+
{
|
13
|
+
class: "flex w-full min-w-0 flex-col gap-1",
|
14
|
+
data: {
|
15
|
+
sidebar: "menu"
|
16
|
+
}
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|