ruby_ui 1.0.1 → 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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -0
  3. data/lib/generators/ruby_ui/component/all_generator.rb +22 -0
  4. data/lib/generators/ruby_ui/component_generator.rb +4 -3
  5. data/lib/generators/ruby_ui/install/install_generator.rb +1 -7
  6. data/lib/generators/ruby_ui/install/templates/tailwind.css.erb +0 -3
  7. data/lib/generators/ruby_ui/javascript_utils.rb +4 -0
  8. data/lib/ruby_ui/alert_dialog/alert_dialog_content.rb +2 -3
  9. data/lib/ruby_ui/button/button.rb +32 -16
  10. data/lib/ruby_ui/checkbox/checkbox.rb +7 -1
  11. data/lib/ruby_ui/combobox/combobox.rb +3 -2
  12. data/lib/ruby_ui/combobox/combobox_checkbox.rb +4 -2
  13. data/lib/ruby_ui/combobox/combobox_controller.js +4 -4
  14. data/lib/ruby_ui/combobox/combobox_item.rb +2 -1
  15. data/lib/ruby_ui/combobox/combobox_radio.rb +8 -1
  16. data/lib/ruby_ui/combobox/combobox_search_input.rb +11 -5
  17. data/lib/ruby_ui/combobox/combobox_toggle_all_checkbox.rb +2 -1
  18. data/lib/ruby_ui/combobox/combobox_trigger.rb +7 -1
  19. data/lib/ruby_ui/command/command_controller.js +0 -1
  20. data/lib/ruby_ui/dialog/dialog_content.rb +2 -3
  21. data/lib/ruby_ui/dialog/dialog_controller.js +1 -1
  22. data/lib/ruby_ui/dropdown_menu/dropdown_menu.rb +9 -0
  23. data/lib/ruby_ui/dropdown_menu/dropdown_menu_content.rb +17 -2
  24. data/lib/ruby_ui/dropdown_menu/dropdown_menu_controller.js +43 -14
  25. data/lib/ruby_ui/form/form_field_label.rb +7 -1
  26. data/lib/ruby_ui/input/input.rb +8 -1
  27. data/lib/ruby_ui/link/link.rb +32 -16
  28. data/lib/ruby_ui/radio_button/radio_button.rb +3 -1
  29. data/lib/ruby_ui/select/select_item.rb +14 -5
  30. data/lib/ruby_ui/select/select_trigger.rb +9 -4
  31. data/lib/ruby_ui/sidebar/collapsible_sidebar.rb +99 -0
  32. data/lib/ruby_ui/sidebar/mobile_sidebar.rb +45 -0
  33. data/lib/ruby_ui/sidebar/non_collapsible_sidebar.rb +17 -0
  34. data/lib/ruby_ui/sidebar/sidebar.rb +29 -0
  35. data/lib/ruby_ui/sidebar/sidebar_content.rb +20 -0
  36. data/lib/ruby_ui/sidebar/sidebar_controller.js +67 -0
  37. data/lib/ruby_ui/sidebar/sidebar_footer.rb +20 -0
  38. data/lib/ruby_ui/sidebar/sidebar_group.rb +20 -0
  39. data/lib/ruby_ui/sidebar/sidebar_group_action.rb +33 -0
  40. data/lib/ruby_ui/sidebar/sidebar_group_content.rb +20 -0
  41. data/lib/ruby_ui/sidebar/sidebar_group_label.rb +26 -0
  42. data/lib/ruby_ui/sidebar/sidebar_header.rb +20 -0
  43. data/lib/ruby_ui/sidebar/sidebar_input.rb +20 -0
  44. data/lib/ruby_ui/sidebar/sidebar_inset.rb +23 -0
  45. data/lib/ruby_ui/sidebar/sidebar_menu.rb +20 -0
  46. data/lib/ruby_ui/sidebar/sidebar_menu_action.rb +48 -0
  47. data/lib/ruby_ui/sidebar/sidebar_menu_badge.rb +30 -0
  48. data/lib/ruby_ui/sidebar/sidebar_menu_button.rb +63 -0
  49. data/lib/ruby_ui/sidebar/sidebar_menu_item.rb +20 -0
  50. data/lib/ruby_ui/sidebar/sidebar_menu_skeleton.rb +36 -0
  51. data/lib/ruby_ui/sidebar/sidebar_menu_sub.rb +24 -0
  52. data/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb +50 -0
  53. data/lib/ruby_ui/sidebar/sidebar_menu_sub_item.rb +9 -0
  54. data/lib/ruby_ui/sidebar/sidebar_rail.rb +36 -0
  55. data/lib/ruby_ui/sidebar/sidebar_separator.rb +20 -0
  56. data/lib/ruby_ui/sidebar/sidebar_trigger.rb +42 -0
  57. data/lib/ruby_ui/sidebar/sidebar_wrapper.rb +24 -0
  58. data/lib/ruby_ui/switch/switch.rb +12 -2
  59. data/lib/ruby_ui/table/table_footer.rb +1 -1
  60. data/lib/ruby_ui/table/table_row.rb +1 -1
  61. data/lib/ruby_ui/tabs/tabs_trigger.rb +7 -1
  62. data/lib/ruby_ui/textarea/textarea.rb +8 -1
  63. data/lib/ruby_ui/tooltip/tooltip_controller.js +5 -4
  64. data/lib/ruby_ui.rb +1 -1
  65. metadata +30 -2
@@ -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: "flex h-9 w-full rounded-md border bg-background px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:outline-none focus-visible:ring-1 disabled:cursor-not-allowed disabled:opacity-50 border-border focus-visible:ring-ring placeholder:text-muted-foreground"
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
@@ -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
- "whitespace-nowrap inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground shadow hover:bg-primary/90",
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
- "whitespace-nowrap inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 text-primary underline-offset-4 hover:underline",
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
- "whitespace-nowrap inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-secondary text-secondary-foreground hover:bg-opacity-80",
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
- "whitespace-nowrap inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
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
- "whitespace-nowrap inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
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
- "whitespace-nowrap inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground",
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
- class: "item group relative flex cursor-pointer select-none items-center 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 aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
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
- data_value: @value,
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 placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
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