ruby_ui 1.0.1 → 1.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.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +6 -0
  4. data/lib/generators/ruby_ui/component/all_generator.rb +22 -0
  5. data/lib/generators/ruby_ui/component_generator.rb +4 -3
  6. data/lib/generators/ruby_ui/install/docs_generator.rb +33 -0
  7. data/lib/generators/ruby_ui/install/install_generator.rb +1 -7
  8. data/lib/generators/ruby_ui/install/templates/tailwind.css.erb +0 -3
  9. data/lib/generators/ruby_ui/javascript_utils.rb +4 -0
  10. data/lib/ruby_ui/accordion/accordion_docs.rb +53 -0
  11. data/lib/ruby_ui/alert/alert_docs.rb +135 -0
  12. data/lib/ruby_ui/alert_dialog/alert_dialog_content.rb +2 -3
  13. data/lib/ruby_ui/alert_dialog/alert_dialog_docs.rb +35 -0
  14. data/lib/ruby_ui/aspect_ratio/aspect_ratio_docs.rb +64 -0
  15. data/lib/ruby_ui/avatar/avatar_docs.rb +92 -0
  16. data/lib/ruby_ui/badge/badge_docs.rb +80 -0
  17. data/lib/ruby_ui/breadcrumb/breadcrumb_docs.rb +116 -0
  18. data/lib/ruby_ui/button/button.rb +32 -16
  19. data/lib/ruby_ui/button/button_docs.rb +143 -0
  20. data/lib/ruby_ui/calendar/calendar_docs.rb +34 -0
  21. data/lib/ruby_ui/card/card_docs.rb +114 -0
  22. data/lib/ruby_ui/carousel/carousel_docs.rb +104 -0
  23. data/lib/ruby_ui/chart/chart_docs.rb +115 -0
  24. data/lib/ruby_ui/checkbox/checkbox.rb +7 -1
  25. data/lib/ruby_ui/checkbox/checkbox_docs.rb +41 -0
  26. data/lib/ruby_ui/clipboard/clipboard_docs.rb +30 -0
  27. data/lib/ruby_ui/codeblock/codeblock_docs.rb +55 -0
  28. data/lib/ruby_ui/collapsible/collapsible_docs.rb +96 -0
  29. data/lib/ruby_ui/combobox/combobox.rb +3 -2
  30. data/lib/ruby_ui/combobox/combobox_checkbox.rb +4 -2
  31. data/lib/ruby_ui/combobox/combobox_controller.js +20 -5
  32. data/lib/ruby_ui/combobox/combobox_docs.rb +151 -0
  33. data/lib/ruby_ui/combobox/combobox_item.rb +2 -1
  34. data/lib/ruby_ui/combobox/combobox_popover.rb +2 -1
  35. data/lib/ruby_ui/combobox/combobox_radio.rb +8 -1
  36. data/lib/ruby_ui/combobox/combobox_search_input.rb +11 -5
  37. data/lib/ruby_ui/combobox/combobox_toggle_all_checkbox.rb +4 -2
  38. data/lib/ruby_ui/combobox/combobox_trigger.rb +8 -2
  39. data/lib/ruby_ui/command/command_controller.js +0 -1
  40. data/lib/ruby_ui/command/command_docs.rb +154 -0
  41. data/lib/ruby_ui/context_menu/context_menu.rb +1 -1
  42. data/lib/ruby_ui/context_menu/context_menu_docs.rb +85 -0
  43. data/lib/ruby_ui/dialog/dialog_content.rb +2 -3
  44. data/lib/ruby_ui/dialog/dialog_controller.js +1 -1
  45. data/lib/ruby_ui/dialog/dialog_docs.rb +102 -0
  46. data/lib/ruby_ui/docs/base.rb +90 -0
  47. data/lib/ruby_ui/docs/component_setup_tabs.rb +15 -0
  48. data/lib/ruby_ui/docs/components_table.rb +13 -0
  49. data/lib/ruby_ui/docs/header.rb +17 -0
  50. data/lib/ruby_ui/docs/sidebar_examples.rb +22 -0
  51. data/lib/ruby_ui/docs/visual_code_example.rb +22 -0
  52. data/lib/ruby_ui/dropdown_menu/dropdown_menu.rb +9 -0
  53. data/lib/ruby_ui/dropdown_menu/dropdown_menu_content.rb +17 -2
  54. data/lib/ruby_ui/dropdown_menu/dropdown_menu_controller.js +43 -14
  55. data/lib/ruby_ui/dropdown_menu/dropdown_menu_docs.rb +212 -0
  56. data/lib/ruby_ui/form/form_docs.rb +178 -0
  57. data/lib/ruby_ui/form/form_field.rb +1 -1
  58. data/lib/ruby_ui/form/form_field_error.rb +1 -1
  59. data/lib/ruby_ui/form/form_field_hint.rb +1 -1
  60. data/lib/ruby_ui/form/form_field_label.rb +7 -1
  61. data/lib/ruby_ui/hover_card/hover_card_docs.rb +71 -0
  62. data/lib/ruby_ui/input/input.rb +9 -1
  63. data/lib/ruby_ui/input/input_docs.rb +68 -0
  64. data/lib/ruby_ui/link/link.rb +32 -16
  65. data/lib/ruby_ui/link/link_docs.rb +106 -0
  66. data/lib/ruby_ui/masked_input/masked_input_docs.rb +47 -0
  67. data/lib/ruby_ui/pagination/pagination_docs.rb +127 -0
  68. data/lib/ruby_ui/popover/popover_docs.rb +971 -0
  69. data/lib/ruby_ui/progress/progress_docs.rb +27 -0
  70. data/lib/ruby_ui/radio_button/radio_button.rb +3 -1
  71. data/lib/ruby_ui/radio_button/radio_button_docs.rb +53 -0
  72. data/lib/ruby_ui/select/select_docs.rb +129 -0
  73. data/lib/ruby_ui/select/select_item.rb +14 -5
  74. data/lib/ruby_ui/select/select_trigger.rb +9 -4
  75. data/lib/ruby_ui/separator/separator_docs.rb +36 -0
  76. data/lib/ruby_ui/sheet/sheet_content.rb +1 -1
  77. data/lib/ruby_ui/sheet/sheet_docs.rb +76 -0
  78. data/lib/ruby_ui/shortcut_key/shortcut_key_docs.rb +29 -0
  79. data/lib/ruby_ui/sidebar/collapsible_sidebar.rb +99 -0
  80. data/lib/ruby_ui/sidebar/mobile_sidebar.rb +45 -0
  81. data/lib/ruby_ui/sidebar/non_collapsible_sidebar.rb +17 -0
  82. data/lib/ruby_ui/sidebar/sidebar.rb +29 -0
  83. data/lib/ruby_ui/sidebar/sidebar_content.rb +20 -0
  84. data/lib/ruby_ui/sidebar/sidebar_controller.js +67 -0
  85. data/lib/ruby_ui/sidebar/sidebar_docs.rb +176 -0
  86. data/lib/ruby_ui/sidebar/sidebar_footer.rb +20 -0
  87. data/lib/ruby_ui/sidebar/sidebar_group.rb +20 -0
  88. data/lib/ruby_ui/sidebar/sidebar_group_action.rb +33 -0
  89. data/lib/ruby_ui/sidebar/sidebar_group_content.rb +20 -0
  90. data/lib/ruby_ui/sidebar/sidebar_group_label.rb +26 -0
  91. data/lib/ruby_ui/sidebar/sidebar_header.rb +20 -0
  92. data/lib/ruby_ui/sidebar/sidebar_input.rb +20 -0
  93. data/lib/ruby_ui/sidebar/sidebar_inset.rb +23 -0
  94. data/lib/ruby_ui/sidebar/sidebar_menu.rb +20 -0
  95. data/lib/ruby_ui/sidebar/sidebar_menu_action.rb +48 -0
  96. data/lib/ruby_ui/sidebar/sidebar_menu_badge.rb +30 -0
  97. data/lib/ruby_ui/sidebar/sidebar_menu_button.rb +63 -0
  98. data/lib/ruby_ui/sidebar/sidebar_menu_item.rb +20 -0
  99. data/lib/ruby_ui/sidebar/sidebar_menu_skeleton.rb +36 -0
  100. data/lib/ruby_ui/sidebar/sidebar_menu_sub.rb +24 -0
  101. data/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb +50 -0
  102. data/lib/ruby_ui/sidebar/sidebar_menu_sub_item.rb +9 -0
  103. data/lib/ruby_ui/sidebar/sidebar_rail.rb +36 -0
  104. data/lib/ruby_ui/sidebar/sidebar_separator.rb +20 -0
  105. data/lib/ruby_ui/sidebar/sidebar_trigger.rb +42 -0
  106. data/lib/ruby_ui/sidebar/sidebar_wrapper.rb +24 -0
  107. data/lib/ruby_ui/skeleton/skeleton_docs.rb +29 -0
  108. data/lib/ruby_ui/switch/switch.rb +12 -2
  109. data/lib/ruby_ui/switch/switch_docs.rb +46 -0
  110. data/lib/ruby_ui/table/table_docs.rb +102 -0
  111. data/lib/ruby_ui/table/table_footer.rb +1 -1
  112. data/lib/ruby_ui/table/table_row.rb +1 -1
  113. data/lib/ruby_ui/tabs/tabs_docs.rb +211 -0
  114. data/lib/ruby_ui/tabs/tabs_trigger.rb +7 -1
  115. data/lib/ruby_ui/textarea/textarea.rb +8 -1
  116. data/lib/ruby_ui/textarea/textarea_docs.rb +54 -0
  117. data/lib/ruby_ui/theme_toggle/theme_toggle_docs.rb +71 -0
  118. data/lib/ruby_ui/tooltip/tooltip_controller.js +5 -4
  119. data/lib/ruby_ui/tooltip/tooltip_docs.rb +52 -0
  120. data/lib/ruby_ui/typography/typography_docs.rb +107 -0
  121. data/lib/ruby_ui.rb +1 -1
  122. metadata +81 -6
@@ -21,11 +21,17 @@ module RubyUI
21
21
  def default_attrs
22
22
  {
23
23
  type: "button",
24
- class: "flex h-full w-full items-center whitespace-nowrap rounded-md text-sm ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-accent hover:text-accent-foreground h-10 px-4 py-2 justify-between",
24
+ class: [
25
+ "flex h-full w-full items-center whitespace-nowrap rounded-md text-sm ring-offset-background transition-colors border border-input bg-background h-9 px-4 py-2 justify-between",
26
+ "hover:bg-accent hover:text-accent-foreground",
27
+ "disabled:pointer-events-none disabled:opacity-50",
28
+ "aria-disabled:pointer-events-none aria-disabled:opacity-50 aria-disabled:cursor-not-allowed",
29
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
30
+ ],
25
31
  data: {
26
32
  placeholder: @placeholder,
27
33
  ruby_ui__combobox_target: "trigger",
28
- action: "ruby-ui--combobox#openPopover"
34
+ action: "ruby-ui--combobox#togglePopover"
29
35
  },
30
36
  aria: {
31
37
  haspopup: "listbox",
@@ -34,7 +34,6 @@ export default class extends Controller {
34
34
  // allow scroll on body
35
35
  document.body.classList.remove("overflow-hidden");
36
36
  // remove the element
37
- console.log("this.element", this.element);
38
37
  this.element.remove();
39
38
  }
40
39
 
@@ -0,0 +1,154 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Views::Docs::Command < Views::Base
4
+ def view_template
5
+ component = "Command"
6
+ div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
7
+ render Docs::Header.new(title: "Command", description: "Fast, composable, unstyled command menu for Phlex.")
8
+
9
+ Heading(level: 2) { "Usage" }
10
+
11
+ render Docs::VisualCodeExample.new(title: "Example", context: self) do
12
+ <<~RUBY
13
+ CommandDialog do
14
+ CommandDialogTrigger do
15
+ Button(variant: "outline", class: 'w-56 pr-2 pl-3 justify-between') do
16
+ div(class: "flex items-center space-x-1") do
17
+ search_icon
18
+ span(class: "text-muted-foreground font-normal") do
19
+ plain "Search"
20
+ end
21
+ end
22
+ ShortcutKey do
23
+ span(class: "text-xs") { "⌘" }
24
+ plain "K"
25
+ end
26
+ end
27
+ end
28
+ CommandDialogContent do
29
+ Command do
30
+ CommandInput(placeholder: "Type a command or search...")
31
+ CommandEmpty { "No results found." }
32
+ CommandList do
33
+ CommandGroup(title: "Components") do
34
+ components_list.each do |component|
35
+ CommandItem(value: component[:name], href: component[:path]) do
36
+ default_icon
37
+ plain component[:name]
38
+ end
39
+ end
40
+ end
41
+ CommandGroup(title: "Settings") do
42
+ settings_list.each do |setting|
43
+ CommandItem(value: setting[:name], href: setting[:path]) do
44
+ default_icon
45
+ plain setting[:name]
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ RUBY
54
+ end
55
+
56
+ render Docs::VisualCodeExample.new(title: "With keybinding", context: self) do
57
+ <<~RUBY
58
+ CommandDialog do
59
+ CommandDialogTrigger(keybindings: ['keydown.ctrl+j@window', 'keydown.meta+j@window']) do
60
+ p(class: "text-sm text-muted-foreground") do
61
+ span(class: 'mr-1') { "Press" }
62
+ ShortcutKey do
63
+ span(class: "text-xs") { "⌘" }
64
+ plain "J"
65
+ end
66
+ end
67
+ end
68
+ CommandDialogContent do
69
+ Command do
70
+ CommandInput(placeholder: "Type a command or search...")
71
+ CommandEmpty { "No results found." }
72
+ CommandList do
73
+ CommandGroup(title: "Components") do
74
+ components_list.each do |component|
75
+ CommandItem(value: component[:name], href: component[:path]) do
76
+ default_icon
77
+ plain component[:name]
78
+ end
79
+ end
80
+ end
81
+ CommandGroup(title: "Settings") do
82
+ settings_list.each do |setting|
83
+ CommandItem(value: setting[:name], href: setting[:path]) do
84
+ default_icon
85
+ plain setting[:name]
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ RUBY
94
+ end
95
+
96
+ render Components::ComponentSetup::Tabs.new(component_name: component)
97
+
98
+ render Docs::ComponentsTable.new(component_files(component))
99
+ end
100
+ end
101
+
102
+ private
103
+
104
+ def search_icon
105
+ svg(
106
+ xmlns: "http://www.w3.org/2000/svg",
107
+ viewbox: "0 0 20 20",
108
+ fill: "currentColor",
109
+ class: "w-4 h-4 mr-1.5"
110
+ ) do |s|
111
+ s.path(
112
+ fill_rule: "evenodd",
113
+ d:
114
+ "M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z",
115
+ clip_rule: "evenodd"
116
+ )
117
+ end
118
+ end
119
+
120
+ def default_icon
121
+ svg(
122
+ xmlns: "http://www.w3.org/2000/svg",
123
+ viewbox: "0 0 24 24",
124
+ fill: "currentColor",
125
+ class: "w-5 h-5"
126
+ ) do |s|
127
+ s.path(
128
+ fill_rule: "evenodd",
129
+ d:
130
+ "M12 2.25c-5.385 0-9.75 4.365-9.75 9.75s4.365 9.75 9.75 9.75 9.75-4.365 9.75-9.75S17.385 2.25 12 2.25zm4.28 10.28a.75.75 0 000-1.06l-3-3a.75.75 0 10-1.06 1.06l1.72 1.72H8.25a.75.75 0 000 1.5h5.69l-1.72 1.72a.75.75 0 101.06 1.06l3-3z",
131
+ clip_rule: "evenodd"
132
+ )
133
+ end
134
+ end
135
+
136
+ def components_list
137
+ [
138
+ {name: "Accordion", path: docs_accordion_path},
139
+ {name: "Alert", path: docs_alert_path},
140
+ {name: "Alert Dialog", path: docs_alert_dialog_path},
141
+ {name: "Aspect Ratio", path: docs_aspect_ratio_path},
142
+ {name: "Avatar", path: docs_avatar_path},
143
+ {name: "Badge", path: docs_badge_path}
144
+ ]
145
+ end
146
+
147
+ def settings_list
148
+ [
149
+ {name: "Profile", path: "#"},
150
+ {name: "Mail", path: "#"},
151
+ {name: "Settings", path: "#"}
152
+ ]
153
+ end
154
+ end
@@ -18,7 +18,7 @@ module RubyUI
18
18
  {
19
19
  data: {
20
20
  controller: "ruby-ui--context-menu",
21
- popover_options_value: @options.to_json
21
+ ruby_ui__context_menu_options_value: @options.to_json
22
22
  }
23
23
  }
24
24
  end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Views::Docs::ContextMenu < Views::Base
4
+ def view_template
5
+ component = "ContextMenu"
6
+ div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
7
+ render Docs::Header.new(title: "Context Menu", description: "Displays a menu to the user — such as a set of actions or functions — triggered by a right click.")
8
+
9
+ Heading(level: 2) { "Usage" }
10
+
11
+ render Docs::VisualCodeExample.new(title: "Example", context: self) do
12
+ <<~RUBY
13
+ ContextMenu do
14
+ ContextMenuTrigger(class: 'flex h-[150px] w-[300px] items-center justify-center rounded-md border border-dashed text-sm') { "Right click here" }
15
+ ContextMenuContent(class: 'w-64') do
16
+ ContextMenuItem(href: '#', shortcut: "⌘[") { "Back" }
17
+ ContextMenuItem(href: '#', shortcut: "⌘]", disabled: true) { "Forward" }
18
+ ContextMenuItem(href: '#', shortcut: "⌘R") { "Reload" }
19
+ ContextMenuSeparator
20
+ ContextMenuItem(href: '#', shortcut: "⌘⇧B", checked: true) { "Show Bookmarks Bar" }
21
+ ContextMenuItem(href: '#') { "Show Full URLs" }
22
+ ContextMenuSeparator
23
+ ContextMenuLabel(inset: true) { "More Tools" }
24
+ ContextMenuSeparator
25
+ ContextMenuItem(href: '#') { "Developer Tools" }
26
+ ContextMenuItem(href: '#') { "Task Manager" }
27
+ ContextMenuItem(href: '#') { "Extensions" }
28
+ end
29
+ end
30
+ RUBY
31
+ end
32
+
33
+ render Docs::VisualCodeExample.new(title: "Placement", context: self) do
34
+ <<~RUBY
35
+ div(class: 'space-y-4') do
36
+ ContextMenu(options: { placement: 'right' }) do
37
+ ContextMenuTrigger(class: 'flex flex-col items-center gap-y-2 h-[150px] w-[300px] items-center justify-center rounded-md border border-dashed text-sm') do
38
+ plain "Right click here"
39
+ Badge(variant: :primary) { "right" }
40
+ end
41
+ ContextMenuContent(class: 'w-64') do
42
+ ContextMenuItem(href: '#', shortcut: "⌘[") { "Back" }
43
+ ContextMenuItem(href: '#', shortcut: "⌘]", disabled: true) { "Forward" }
44
+ ContextMenuItem(href: '#', shortcut: "⌘R") { "Reload" }
45
+ ContextMenuSeparator
46
+ ContextMenuItem(href: '#', shortcut: "⌘⇧B", checked: true) { "Show Bookmarks Bar" }
47
+ ContextMenuItem(href: '#') { "Show Full URLs" }
48
+ ContextMenuSeparator
49
+ ContextMenuLabel(inset: true) { "More Tools" }
50
+ ContextMenuSeparator
51
+ ContextMenuItem(href: '#') { "Developer Tools" }
52
+ ContextMenuItem(href: '#') { "Task Manager" }
53
+ ContextMenuItem(href: '#') { "Extensions" }
54
+ end
55
+ end
56
+ ContextMenu(options: { placement: 'left' }) do
57
+ ContextMenuTrigger(class: 'flex flex-col items-center gap-y-2 h-[150px] w-[300px] items-center justify-center rounded-md border border-dashed text-sm') do
58
+ plain "Right click here"
59
+ Badge(variant: :primary) { "left" }
60
+ end
61
+ ContextMenuContent(class: 'w-64') do
62
+ ContextMenuItem(href: '#', shortcut: "⌘[") { "Back" }
63
+ ContextMenuItem(href: '#', shortcut: "⌘]", disabled: true) { "Forward" }
64
+ ContextMenuItem(href: '#', shortcut: "⌘R") { "Reload" }
65
+ ContextMenuSeparator
66
+ ContextMenuItem(href: '#', shortcut: "⌘⇧B", checked: true) { "Show Bookmarks Bar" }
67
+ ContextMenuItem(href: '#') { "Show Full URLs" }
68
+ ContextMenuSeparator
69
+ ContextMenuLabel(inset: true) { "More Tools" }
70
+ ContextMenuSeparator
71
+ ContextMenuItem(href: '#') { "Developer Tools" }
72
+ ContextMenuItem(href: '#') { "Task Manager" }
73
+ ContextMenuItem(href: '#') { "Extensions" }
74
+ end
75
+ end
76
+ end
77
+ RUBY
78
+ end
79
+
80
+ render Components::ComponentSetup::Tabs.new(component_name: component)
81
+
82
+ render Docs::ComponentsTable.new(component_files(component))
83
+ end
84
+ end
85
+ end
@@ -34,7 +34,7 @@ module RubyUI
34
34
  {
35
35
  data_state: "open",
36
36
  class: [
37
- "fixed flex flex-col pointer-events-auto left-[50%] top-[50%] z-50 w-full max-h-screen overflow-y-auto translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full",
37
+ "fixed flex flex-col pointer-events-auto left-[50%] top-[50%] z-50 w-full max-h-screen overflow-y-auto translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 sm:rounded-lg md:w-full",
38
38
  SIZES[@size]
39
39
  ]
40
40
  }
@@ -70,8 +70,7 @@ module RubyUI
70
70
  div(
71
71
  data_state: "open",
72
72
  data_action: "click->ruby-ui--dialog#dismiss esc->ruby-ui--dialog#dismiss",
73
- class:
74
- "fixed pointer-events-auto inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
73
+ class: "fixed pointer-events-auto inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=open]:fade-in-0"
75
74
  )
76
75
  end
77
76
  end
@@ -17,7 +17,7 @@ export default class extends Controller {
17
17
  }
18
18
 
19
19
  open(e) {
20
- e.preventDefault()
20
+ e?.preventDefault();
21
21
  document.body.insertAdjacentHTML('beforeend', this.contentTarget.innerHTML)
22
22
  // prevent scroll on body
23
23
  document.body.classList.add('overflow-hidden')
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Views::Docs::Dialog < Views::Base
4
+ def view_template
5
+ component = "Dialog"
6
+
7
+ div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
8
+ render Docs::Header.new(title: "Dialog", description: "A window overlaid on either the primary window or another dialog window, rendering the content underneath inert.")
9
+
10
+ Heading(level: 2) { "Usage" }
11
+
12
+ render Docs::VisualCodeExample.new(title: "Example", context: self) do
13
+ <<~RUBY
14
+ Dialog do
15
+ DialogTrigger do
16
+ Button { "Open Dialog" }
17
+ end
18
+ DialogContent do
19
+ DialogHeader do
20
+ DialogTitle { "RubyUI to the rescue" }
21
+ DialogDescription { "RubyUI helps you build accessible standard compliant web apps with ease" }
22
+ end
23
+ DialogMiddle do
24
+ AspectRatio(aspect_ratio: "16/9", class: 'rounded-md overflow-hidden border') do
25
+ img(
26
+ alt: "Placeholder",
27
+ loading: "lazy",
28
+ src: image_path("pattern.jpg")
29
+ )
30
+ end
31
+ end
32
+ DialogFooter do
33
+ Button(variant: :outline, data: { action: 'click->ruby-ui--dialog#dismiss' }) { "Cancel" }
34
+ Button { "Save" }
35
+ end
36
+ end
37
+ end
38
+ RUBY
39
+ end
40
+
41
+ render Docs::VisualCodeExample.new(title: "Size", description: "Applicable for wider screens", context: self) do
42
+ <<~RUBY
43
+ div(class: 'flex flex-wrap justify-center gap-2') do
44
+ Dialog do
45
+ DialogTrigger do
46
+ Button { "Small Dialog" }
47
+ end
48
+ DialogContent(size: :sm) do
49
+ DialogHeader do
50
+ DialogTitle { "RubyUI to the rescue" }
51
+ DialogDescription { "RubyUI helps you build accessible standard compliant web apps with ease" }
52
+ end
53
+ DialogMiddle do
54
+ AspectRatio(aspect_ratio: "16/9", class: 'rounded-md overflow-hidden border') do
55
+ img(
56
+ alt: "Placeholder",
57
+ loading: "lazy",
58
+ src: image_path("pattern.jpg")
59
+ )
60
+ end
61
+ end
62
+ DialogFooter do
63
+ Button(variant: :outline, data: { action: 'click->ruby-ui--dialog#dismiss' }) { "Cancel" }
64
+ Button { "Save" }
65
+ end
66
+ end
67
+ end
68
+
69
+ Dialog do
70
+ DialogTrigger do
71
+ Button { "Large Dialog" }
72
+ end
73
+ DialogContent(size: :lg) do
74
+ DialogHeader do
75
+ DialogTitle { "RubyUI to the rescue" }
76
+ DialogDescription { "RubyUI helps you build accessible standard compliant web apps with ease" }
77
+ end
78
+ DialogMiddle do
79
+ AspectRatio(aspect_ratio: "16/9", class: 'rounded-md overflow-hidden border') do
80
+ img(
81
+ alt: "Placeholder",
82
+ loading: "lazy",
83
+ src: image_path("pattern.jpg")
84
+ )
85
+ end
86
+ end
87
+ DialogFooter do
88
+ Button(variant: :outline, data: { action: 'click->ruby-ui--dialog#dismiss' }) { "Cancel" }
89
+ Button { "Save" }
90
+ end
91
+ end
92
+ end
93
+ end
94
+ RUBY
95
+ end
96
+
97
+ render Components::ComponentSetup::Tabs.new(component_name: component)
98
+
99
+ render Docs::ComponentsTable.new(component_files(component))
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Views
4
+ class Base < Phlex::HTML
5
+ def Heading(level:, &)
6
+ tag = :"h#{level}"
7
+ send(tag, &)
8
+ end
9
+
10
+ def component_files(component_name)
11
+ []
12
+ end
13
+
14
+ # Text helper for wrapping paragraphs
15
+ def Text(&)
16
+ p(&)
17
+ end
18
+
19
+ # InlineLink helper for documentation links
20
+ def InlineLink(href:, target: nil, class: nil, &)
21
+ a(href: href, target: target, class: binding.local_variable_get(:class), &)
22
+ end
23
+
24
+ # Alert component helpers
25
+ def Alert(&)
26
+ div(&)
27
+ end
28
+
29
+ def AlertTitle(&)
30
+ h4(&)
31
+ end
32
+
33
+ def AlertDescription(&)
34
+ p(&)
35
+ end
36
+
37
+ # Route helper stubs - return "#" as placeholder
38
+ def docs_sheet_path
39
+ "#"
40
+ end
41
+
42
+ def docs_separator_path
43
+ "#"
44
+ end
45
+
46
+ def docs_accordion_path
47
+ "#"
48
+ end
49
+
50
+ def docs_alert_path
51
+ "#"
52
+ end
53
+
54
+ def docs_alert_dialog_path
55
+ "#"
56
+ end
57
+
58
+ def docs_aspect_ratio_path
59
+ "#"
60
+ end
61
+
62
+ def docs_avatar_path
63
+ "#"
64
+ end
65
+
66
+ def docs_badge_path
67
+ "#"
68
+ end
69
+
70
+ def docs_installation_path
71
+ "#"
72
+ end
73
+
74
+ # InlineCode helper for typography examples
75
+ def InlineCode(&)
76
+ code(&)
77
+ end
78
+ end
79
+ end
80
+
81
+ # Module-level components stub
82
+ module Components
83
+ def self.Heading(level:, &block)
84
+ # Stub for module-level Heading calls
85
+ end
86
+
87
+ def self.TypographyList(items:, numbered: false)
88
+ # Stub for TypographyList component
89
+ end
90
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Components
4
+ module ComponentSetup
5
+ class Tabs < Phlex::HTML
6
+ def initialize(component_name:)
7
+ @component_name = component_name
8
+ end
9
+
10
+ def view_template
11
+ # Minimal stub - empty by default
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Docs
4
+ class ComponentsTable < Phlex::HTML
5
+ def initialize(files)
6
+ @files = files
7
+ end
8
+
9
+ def view_template
10
+ # Minimal stub - empty by default
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Docs
4
+ class Header < Phlex::HTML
5
+ def initialize(title:, description: nil)
6
+ @title = title
7
+ @description = description
8
+ end
9
+
10
+ def view_template
11
+ div do
12
+ h1 { @title }
13
+ p { @description } if @description
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Stub constants for sidebar documentation examples
4
+ # These are replaced with actual implementations in the web app
5
+
6
+ module Views
7
+ module Docs
8
+ class Sidebar < Views::Base
9
+ class Example
10
+ CODE = <<~RUBY
11
+ # Sidebar example code placeholder
12
+ RUBY
13
+ end
14
+
15
+ class InsetExample
16
+ CODE = <<~RUBY
17
+ # Sidebar inset example code placeholder
18
+ RUBY
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Docs
4
+ class VisualCodeExample < Phlex::HTML
5
+ def initialize(title:, context:, description: nil, src: nil)
6
+ @title = title
7
+ @context = context
8
+ @description = description
9
+ @src = src
10
+ end
11
+
12
+ def view_template(&block)
13
+ code = block.call
14
+ div do
15
+ h3 { @title }
16
+ p { @description } if @description
17
+ pre { code }
18
+ @context.instance_eval(code)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -15,6 +15,11 @@ module RubyUI
15
15
 
16
16
  def default_attrs
17
17
  {
18
+ class: [
19
+ "z-50",
20
+ "group/dropdown-menu",
21
+ (strategy == "absolute") ? "is-absolute" : "is-fixed"
22
+ ],
18
23
  data: {
19
24
  controller: "ruby-ui--dropdown-menu",
20
25
  action: "click@window->ruby-ui--dropdown-menu#onClickOutside",
@@ -22,5 +27,9 @@ module RubyUI
22
27
  }
23
28
  }
24
29
  end
30
+
31
+ def strategy
32
+ @_strategy ||= @options[:strategy] || "absolute"
33
+ end
25
34
  end
26
35
  end
@@ -3,7 +3,7 @@
3
3
  module RubyUI
4
4
  class DropdownMenuContent < Base
5
5
  def view_template(&block)
6
- div(data: {ruby_ui__dropdown_menu_target: "content"}, class: "hidden", style: "width: max-content; position: absolute; top: 0; left: 0;") do
6
+ div(**wrapper_attrs) do
7
7
  div(**attrs, &block)
8
8
  end
9
9
  end
@@ -15,7 +15,22 @@ module RubyUI
15
15
  data: {
16
16
  state: :open
17
17
  },
18
- class: "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-background p-1 text-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 w-56"
18
+ class: "z-50 min-w-[8rem] rounded-md border bg-background p-1 text-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 w-56"
19
+ }
20
+ end
21
+
22
+ def wrapper_attrs
23
+ {
24
+ class: [
25
+ "z-50 hidden group-[.is-absolute]/dropdown-menu:absolute",
26
+ "group-[.is-fixed]/dropdown-menu:fixed"
27
+ ],
28
+ data: {ruby_ui__dropdown_menu_target: "content"},
29
+ style: {
30
+ width: "max-content",
31
+ top: "0",
32
+ left: "0"
33
+ }
19
34
  }
20
35
  end
21
36
  end