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.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +6 -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/docs_generator.rb +33 -0
- 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/accordion/accordion_docs.rb +53 -0
- data/lib/ruby_ui/alert/alert_docs.rb +135 -0
- data/lib/ruby_ui/alert_dialog/alert_dialog_content.rb +2 -3
- data/lib/ruby_ui/alert_dialog/alert_dialog_docs.rb +35 -0
- data/lib/ruby_ui/aspect_ratio/aspect_ratio_docs.rb +64 -0
- data/lib/ruby_ui/avatar/avatar_docs.rb +92 -0
- data/lib/ruby_ui/badge/badge_docs.rb +80 -0
- data/lib/ruby_ui/breadcrumb/breadcrumb_docs.rb +116 -0
- data/lib/ruby_ui/button/button.rb +32 -16
- data/lib/ruby_ui/button/button_docs.rb +143 -0
- data/lib/ruby_ui/calendar/calendar_docs.rb +34 -0
- data/lib/ruby_ui/card/card_docs.rb +114 -0
- data/lib/ruby_ui/carousel/carousel_docs.rb +104 -0
- data/lib/ruby_ui/chart/chart_docs.rb +115 -0
- data/lib/ruby_ui/checkbox/checkbox.rb +7 -1
- data/lib/ruby_ui/checkbox/checkbox_docs.rb +41 -0
- data/lib/ruby_ui/clipboard/clipboard_docs.rb +30 -0
- data/lib/ruby_ui/codeblock/codeblock_docs.rb +55 -0
- data/lib/ruby_ui/collapsible/collapsible_docs.rb +96 -0
- 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 +20 -5
- data/lib/ruby_ui/combobox/combobox_docs.rb +151 -0
- data/lib/ruby_ui/combobox/combobox_item.rb +2 -1
- data/lib/ruby_ui/combobox/combobox_popover.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 +4 -2
- data/lib/ruby_ui/combobox/combobox_trigger.rb +8 -2
- data/lib/ruby_ui/command/command_controller.js +0 -1
- data/lib/ruby_ui/command/command_docs.rb +154 -0
- data/lib/ruby_ui/context_menu/context_menu.rb +1 -1
- data/lib/ruby_ui/context_menu/context_menu_docs.rb +85 -0
- data/lib/ruby_ui/dialog/dialog_content.rb +2 -3
- data/lib/ruby_ui/dialog/dialog_controller.js +1 -1
- data/lib/ruby_ui/dialog/dialog_docs.rb +102 -0
- data/lib/ruby_ui/docs/base.rb +90 -0
- data/lib/ruby_ui/docs/component_setup_tabs.rb +15 -0
- data/lib/ruby_ui/docs/components_table.rb +13 -0
- data/lib/ruby_ui/docs/header.rb +17 -0
- data/lib/ruby_ui/docs/sidebar_examples.rb +22 -0
- data/lib/ruby_ui/docs/visual_code_example.rb +22 -0
- 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/dropdown_menu/dropdown_menu_docs.rb +212 -0
- data/lib/ruby_ui/form/form_docs.rb +178 -0
- data/lib/ruby_ui/form/form_field.rb +1 -1
- data/lib/ruby_ui/form/form_field_error.rb +1 -1
- data/lib/ruby_ui/form/form_field_hint.rb +1 -1
- data/lib/ruby_ui/form/form_field_label.rb +7 -1
- data/lib/ruby_ui/hover_card/hover_card_docs.rb +71 -0
- data/lib/ruby_ui/input/input.rb +9 -1
- data/lib/ruby_ui/input/input_docs.rb +68 -0
- data/lib/ruby_ui/link/link.rb +32 -16
- data/lib/ruby_ui/link/link_docs.rb +106 -0
- data/lib/ruby_ui/masked_input/masked_input_docs.rb +47 -0
- data/lib/ruby_ui/pagination/pagination_docs.rb +127 -0
- data/lib/ruby_ui/popover/popover_docs.rb +971 -0
- data/lib/ruby_ui/progress/progress_docs.rb +27 -0
- data/lib/ruby_ui/radio_button/radio_button.rb +3 -1
- data/lib/ruby_ui/radio_button/radio_button_docs.rb +53 -0
- data/lib/ruby_ui/select/select_docs.rb +129 -0
- data/lib/ruby_ui/select/select_item.rb +14 -5
- data/lib/ruby_ui/select/select_trigger.rb +9 -4
- data/lib/ruby_ui/separator/separator_docs.rb +36 -0
- data/lib/ruby_ui/sheet/sheet_content.rb +1 -1
- data/lib/ruby_ui/sheet/sheet_docs.rb +76 -0
- data/lib/ruby_ui/shortcut_key/shortcut_key_docs.rb +29 -0
- 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_docs.rb +176 -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/skeleton/skeleton_docs.rb +29 -0
- data/lib/ruby_ui/switch/switch.rb +12 -2
- data/lib/ruby_ui/switch/switch_docs.rb +46 -0
- data/lib/ruby_ui/table/table_docs.rb +102 -0
- 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_docs.rb +211 -0
- data/lib/ruby_ui/tabs/tabs_trigger.rb +7 -1
- data/lib/ruby_ui/textarea/textarea.rb +8 -1
- data/lib/ruby_ui/textarea/textarea_docs.rb +54 -0
- data/lib/ruby_ui/theme_toggle/theme_toggle_docs.rb +71 -0
- data/lib/ruby_ui/tooltip/tooltip_controller.js +5 -4
- data/lib/ruby_ui/tooltip/tooltip_docs.rb +52 -0
- data/lib/ruby_ui/typography/typography_docs.rb +107 -0
- data/lib/ruby_ui.rb +1 -1
- metadata +81 -6
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Views::Docs::Chart < Views::Base
|
|
4
|
+
def view_template
|
|
5
|
+
div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
|
|
6
|
+
render Docs::Header.new(title: "Chart", description: "Displays information in a visual way.")
|
|
7
|
+
|
|
8
|
+
Heading(level: 2) { "Introduction" }
|
|
9
|
+
|
|
10
|
+
Text do
|
|
11
|
+
plain "RubyUI uses "
|
|
12
|
+
InlineLink(href: "https://www.chartjs.org/") { "Chart.js" }
|
|
13
|
+
plain " to render charts. Chart.js is a free open-source JavaScript library for data visualization, which supports 8 chart types: bar, line, area, pie, bubble, radar, polar, and scatter. If you're unfamiliar with Chart.js. We recommend the "
|
|
14
|
+
InlineLink(href: "https://www.chartjs.org/docs/latest/getting-started/") { "Getting Started guide" }
|
|
15
|
+
plain ". "
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
Heading(level: 2) { "Usage" }
|
|
19
|
+
|
|
20
|
+
render Docs::VisualCodeExample.new(title: "Bar Chart", context: self) do
|
|
21
|
+
<<~RUBY
|
|
22
|
+
options = {
|
|
23
|
+
type: 'bar',
|
|
24
|
+
data: {
|
|
25
|
+
labels: ['Phlex', 'VC', 'ERB'],
|
|
26
|
+
datasets: [{
|
|
27
|
+
label: 'render time (ms)',
|
|
28
|
+
data: [100, 520, 1200],
|
|
29
|
+
}]
|
|
30
|
+
},
|
|
31
|
+
options: {
|
|
32
|
+
indexAxis: 'y',
|
|
33
|
+
scales: {
|
|
34
|
+
y: {
|
|
35
|
+
beginAtZero: true
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
Chart(options: options)
|
|
42
|
+
RUBY
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
render Docs::VisualCodeExample.new(title: "Line Graph", context: self) do
|
|
46
|
+
<<~RUBY
|
|
47
|
+
options = {
|
|
48
|
+
type: 'line',
|
|
49
|
+
data: {
|
|
50
|
+
labels: ['Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'],
|
|
51
|
+
datasets: [{
|
|
52
|
+
label: 'Github Stars',
|
|
53
|
+
data: [40, 30, 79, 140, 290, 550],
|
|
54
|
+
}]
|
|
55
|
+
},
|
|
56
|
+
options: {
|
|
57
|
+
scales: {
|
|
58
|
+
y: {
|
|
59
|
+
beginAtZero: true
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
plugins: {
|
|
63
|
+
legend: {
|
|
64
|
+
display: false
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
Chart(options: options)
|
|
71
|
+
RUBY
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
render Docs::VisualCodeExample.new(title: "Pie Chart", description: "Setting custom background color", context: self) do
|
|
75
|
+
<<~RUBY
|
|
76
|
+
options = {
|
|
77
|
+
type: 'pie',
|
|
78
|
+
data: {
|
|
79
|
+
labels: [
|
|
80
|
+
'Red',
|
|
81
|
+
'Blue',
|
|
82
|
+
'Yellow'
|
|
83
|
+
],
|
|
84
|
+
datasets: [{
|
|
85
|
+
label: 'My First Dataset',
|
|
86
|
+
data: [300, 50, 100],
|
|
87
|
+
backgroundColor: [
|
|
88
|
+
'rgb(255, 99, 132)',
|
|
89
|
+
'rgb(54, 162, 235)',
|
|
90
|
+
'rgb(255, 205, 86)'
|
|
91
|
+
],
|
|
92
|
+
hoverOffset: 4
|
|
93
|
+
}]
|
|
94
|
+
},
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
Chart(options: options)
|
|
98
|
+
RUBY
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
render Components::ComponentSetup::Tabs.new(component_name: "Chart")
|
|
102
|
+
|
|
103
|
+
render Docs::ComponentsTable.new(components)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
private
|
|
108
|
+
|
|
109
|
+
def components
|
|
110
|
+
[
|
|
111
|
+
::Docs::ComponentStruct.new(name: "ChartController", source: "https://github.com/PhlexUI/phlex_ui_stimulus/blob/main/controllers/chart_controller.js", built_using: :stimulus),
|
|
112
|
+
::Docs::ComponentStruct.new(name: "Chart", source: "https://github.com/PhlexUI/phlex_ui/blob/main/lib/phlex_ui/chart.rb", built_using: :phlex)
|
|
113
|
+
]
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -16,7 +16,13 @@ module RubyUI
|
|
|
16
16
|
ruby_ui__checkbox_group_target: "checkbox",
|
|
17
17
|
action: "change->ruby-ui--checkbox-group#onChange change->ruby-ui--form-field#onInput invalid->ruby-ui--form-field#onInvalid"
|
|
18
18
|
},
|
|
19
|
-
class:
|
|
19
|
+
class: [
|
|
20
|
+
"peer h-4 w-4 shrink-0 rounded-sm border-input ring-offset-background accent-primary",
|
|
21
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
22
|
+
"checked:bg-primary checked:text-primary-foreground dark:checked:bg-secondary checked:text-primary checked:border-primary",
|
|
23
|
+
"aria-disabled:cursor-not-allowed aria-disabled:opacity-50 aria-disabled:pointer-events-none",
|
|
24
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
|
25
|
+
]
|
|
20
26
|
}
|
|
21
27
|
end
|
|
22
28
|
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Views::Docs::Checkbox < Views::Base
|
|
4
|
+
def view_template
|
|
5
|
+
component = "Checkbox"
|
|
6
|
+
div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
|
|
7
|
+
render Docs::Header.new(title: "Checkbox", description: "A control that allows the user to toggle between checked and not checked.")
|
|
8
|
+
|
|
9
|
+
Heading(level: 2) { "Usage" }
|
|
10
|
+
|
|
11
|
+
render Docs::VisualCodeExample.new(title: "Example", context: self) do
|
|
12
|
+
<<~RUBY
|
|
13
|
+
div(class: 'flex items-center space-x-3') do
|
|
14
|
+
Checkbox(id: 'terms')
|
|
15
|
+
label(for: 'terms', class: 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70') { "Accept terms and conditions" }
|
|
16
|
+
end
|
|
17
|
+
RUBY
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
render Docs::VisualCodeExample.new(title: "Checked", context: self) do
|
|
21
|
+
<<~RUBY
|
|
22
|
+
div(class: "items-top flex space-x-3") do
|
|
23
|
+
Checkbox(id: 'terms1', checked: true)
|
|
24
|
+
div(class: "grid gap-1.5 leading-none") do
|
|
25
|
+
label(
|
|
26
|
+
for: "terms1",
|
|
27
|
+
class:
|
|
28
|
+
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
|
29
|
+
) { " Accept terms and conditions " }
|
|
30
|
+
p(class: "text-sm text-muted-foreground") { " You agree to our Terms of Service and Privacy Policy." }
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
RUBY
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
render Components::ComponentSetup::Tabs.new(component_name: component)
|
|
37
|
+
|
|
38
|
+
render Docs::ComponentsTable.new(component_files(component))
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Views::Docs::Clipboard < Views::Base
|
|
4
|
+
def view_template
|
|
5
|
+
component = "Clipboard"
|
|
6
|
+
div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
|
|
7
|
+
render Docs::Header.new(title: "Clipboard", description: "A control to allow you to copy content to the clipboard.")
|
|
8
|
+
|
|
9
|
+
Heading(level: 2) { "Usage" }
|
|
10
|
+
|
|
11
|
+
render Docs::VisualCodeExample.new(title: "Example", context: self) do
|
|
12
|
+
<<~RUBY
|
|
13
|
+
Clipboard(success: "Copied!", error: "Copy failed!", class: "relative", options: {placement: "top"}) do
|
|
14
|
+
ClipboardSource(class: "hidden") { span { "Born rich!!!" } }
|
|
15
|
+
|
|
16
|
+
ClipboardTrigger do
|
|
17
|
+
Link(href: "#", class: "gap-1") do
|
|
18
|
+
Text(size: :small, class: "text-primary") { "Copy the secret of success!!!" }
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
RUBY
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
render Components::ComponentSetup::Tabs.new(component_name: component)
|
|
26
|
+
|
|
27
|
+
render Docs::ComponentsTable.new(component_files(component))
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Views::Docs::Codeblock < Views::Base
|
|
4
|
+
def view_template
|
|
5
|
+
component = "Codeblock"
|
|
6
|
+
div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
|
|
7
|
+
render Docs::Header.new(title: "Codeblock", description: "A component for displaying highlighted code.")
|
|
8
|
+
|
|
9
|
+
Heading(level: 2) { "Usage" }
|
|
10
|
+
|
|
11
|
+
render Docs::VisualCodeExample.new(title: "With clipboard", context: self) do
|
|
12
|
+
<<~RUBY
|
|
13
|
+
code = <<~CODE
|
|
14
|
+
def hello_world
|
|
15
|
+
puts "Hello, world!"
|
|
16
|
+
end
|
|
17
|
+
CODE
|
|
18
|
+
div(class: 'w-full') do
|
|
19
|
+
Codeblock(code, syntax: :ruby)
|
|
20
|
+
end
|
|
21
|
+
RUBY
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
render Docs::VisualCodeExample.new(title: "Without clipboard", context: self) do
|
|
25
|
+
<<~RUBY
|
|
26
|
+
code = <<~CODE
|
|
27
|
+
def hello_world
|
|
28
|
+
puts "Hello, world!"
|
|
29
|
+
end
|
|
30
|
+
CODE
|
|
31
|
+
div(class: 'w-full') do
|
|
32
|
+
Codeblock(code, syntax: :ruby, clipboard: false)
|
|
33
|
+
end
|
|
34
|
+
RUBY
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
render Docs::VisualCodeExample.new(title: "Custom message", description: "Copy the code to see the message", context: self) do
|
|
38
|
+
<<~RUBY
|
|
39
|
+
code = <<~CODE
|
|
40
|
+
def hello_world
|
|
41
|
+
puts "Hello, world!"
|
|
42
|
+
end
|
|
43
|
+
CODE
|
|
44
|
+
div(class: 'w-full') do
|
|
45
|
+
Codeblock(code, syntax: :ruby, clipboard_success: "Nice one!")
|
|
46
|
+
end
|
|
47
|
+
RUBY
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
render Components::ComponentSetup::Tabs.new(component_name: component)
|
|
51
|
+
|
|
52
|
+
render Docs::ComponentsTable.new(component_files(component))
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Views::Docs::Collapsible < Views::Base
|
|
4
|
+
def view_template
|
|
5
|
+
component = "Collapsible"
|
|
6
|
+
div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
|
|
7
|
+
render Docs::Header.new(title: "Collapsible", description: "An interactive component which expands/collapses a panel.")
|
|
8
|
+
|
|
9
|
+
Heading(level: 2) { "Usage" }
|
|
10
|
+
|
|
11
|
+
render Docs::VisualCodeExample.new(title: "Example", context: self) do
|
|
12
|
+
<<~RUBY
|
|
13
|
+
Collapsible do
|
|
14
|
+
div(class: "flex items-center justify-between space-x-4 px-4 py-2") do
|
|
15
|
+
h4(class: "text-sm font-semibold") { " @joeldrapper starred 3 repositories" }
|
|
16
|
+
CollapsibleTrigger do
|
|
17
|
+
Button(variant: :ghost, icon: true) do
|
|
18
|
+
chevron_icon
|
|
19
|
+
span(class: "sr-only") { "Toggle" }
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
div(class: "rounded-md border px-4 py-2 font-mono text-sm shadow-sm") do
|
|
25
|
+
"phlex-ruby/phlex"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
CollapsibleContent do
|
|
29
|
+
div(class: 'space-y-2 mt-2') do
|
|
30
|
+
div(class: "rounded-md border px-4 py-2 font-mono text-sm shadow-sm") do
|
|
31
|
+
"phlex-ruby/phlex-rails"
|
|
32
|
+
end
|
|
33
|
+
div(class: "rounded-md border px-4 py-2 font-mono text-sm shadow-sm") do
|
|
34
|
+
"ruby-ui/ruby_ui"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
RUBY
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
render Docs::VisualCodeExample.new(title: "Open", context: self) do
|
|
43
|
+
<<~RUBY
|
|
44
|
+
Collapsible(open: true) do
|
|
45
|
+
div(class: "flex items-center justify-between space-x-4 px-4 py-2") do
|
|
46
|
+
h4(class: "text-sm font-semibold") { " @joeldrapper starred 3 repositories" }
|
|
47
|
+
CollapsibleTrigger do
|
|
48
|
+
Button(variant: :ghost, icon: true) do
|
|
49
|
+
chevron_icon
|
|
50
|
+
span(class: "sr-only") { "Toggle" }
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
div(class: "rounded-md border px-4 py-2 font-mono text-sm shadow-sm") do
|
|
56
|
+
"phlex-ruby/phlex"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
CollapsibleContent do
|
|
60
|
+
div(class: 'space-y-2 mt-2') do
|
|
61
|
+
div(class: "rounded-md border px-4 py-2 font-mono text-sm shadow-sm") do
|
|
62
|
+
"phlex-ruby/phlex-rails"
|
|
63
|
+
end
|
|
64
|
+
div(class: "rounded-md border px-4 py-2 font-mono text-sm shadow-sm") do
|
|
65
|
+
"ruby-ui/ruby_ui"
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
RUBY
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
render Components::ComponentSetup::Tabs.new(component_name: component)
|
|
74
|
+
|
|
75
|
+
render Docs::ComponentsTable.new(component_files(component))
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
private
|
|
80
|
+
|
|
81
|
+
def chevron_icon
|
|
82
|
+
svg(
|
|
83
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
84
|
+
viewbox: "0 0 20 20",
|
|
85
|
+
fill: "currentColor",
|
|
86
|
+
class: "w-4 h-4"
|
|
87
|
+
) do |s|
|
|
88
|
+
s.path(
|
|
89
|
+
fill_rule: "evenodd",
|
|
90
|
+
d:
|
|
91
|
+
"M10 3a.75.75 0 01.55.24l3.25 3.5a.75.75 0 11-1.1 1.02L10 4.852 7.3 7.76a.75.75 0 01-1.1-1.02l3.25-3.5A.75.75 0 0110 3zm-3.76 9.2a.75.75 0 011.06.04l2.7 2.908 2.7-2.908a.75.75 0 111.1 1.02l-3.25 3.5a.75.75 0 01-1.1 0l-3.25-3.5a.75.75 0 01.04-1.06z",
|
|
92
|
+
clip_rule: "evenodd"
|
|
93
|
+
)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module RubyUI
|
|
4
4
|
class Combobox < Base
|
|
5
|
-
def initialize(term:
|
|
5
|
+
def initialize(term: nil, **)
|
|
6
6
|
@term = term
|
|
7
7
|
super(**)
|
|
8
8
|
end
|
|
@@ -18,7 +18,8 @@ module RubyUI
|
|
|
18
18
|
role: "combobox",
|
|
19
19
|
data: {
|
|
20
20
|
controller: "ruby-ui--combobox",
|
|
21
|
-
ruby_ui__combobox_term_value: @term
|
|
21
|
+
ruby_ui__combobox_term_value: @term,
|
|
22
|
+
action: "turbo:morph@window->ruby-ui--combobox#updateTriggerContent"
|
|
22
23
|
}
|
|
23
24
|
}
|
|
24
25
|
end
|
|
@@ -12,8 +12,10 @@ module RubyUI
|
|
|
12
12
|
{
|
|
13
13
|
class: [
|
|
14
14
|
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background accent-primary",
|
|
15
|
-
"
|
|
16
|
-
"
|
|
15
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
16
|
+
"checked:bg-primary checked:text-primary-foreground",
|
|
17
|
+
"aria-disabled:cursor-not-allowed aria-disabled:opacity-50 aria-disabled:pointer-events-none",
|
|
18
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
|
17
19
|
],
|
|
18
20
|
data: {
|
|
19
21
|
ruby_ui__combobox_target: "input",
|
|
@@ -28,6 +28,11 @@ export default class extends Controller {
|
|
|
28
28
|
if (this.cleanup) { this.cleanup() }
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
handlePopoverToggle(event) {
|
|
32
|
+
// Keep ariaExpanded in sync with the actual popover state
|
|
33
|
+
this.triggerTarget.ariaExpanded = event.newState === 'open' ? 'true' : 'false'
|
|
34
|
+
}
|
|
35
|
+
|
|
31
36
|
inputChanged(e) {
|
|
32
37
|
this.updateTriggerContent()
|
|
33
38
|
|
|
@@ -53,18 +58,28 @@ export default class extends Controller {
|
|
|
53
58
|
updateTriggerContent() {
|
|
54
59
|
const checkedInputs = this.inputTargets.filter(input => input.checked)
|
|
55
60
|
|
|
56
|
-
if (checkedInputs.length
|
|
61
|
+
if (checkedInputs.length === 0) {
|
|
57
62
|
this.triggerContentTarget.innerText = this.triggerTarget.dataset.placeholder
|
|
58
|
-
} else if (checkedInputs.length
|
|
59
|
-
this.triggerContentTarget.innerText = this.inputContent(checkedInputs[0])
|
|
60
|
-
} else {
|
|
63
|
+
} else if (this.termValue && checkedInputs.length > 1) {
|
|
61
64
|
this.triggerContentTarget.innerText = `${checkedInputs.length} ${this.termValue}`
|
|
65
|
+
} else {
|
|
66
|
+
this.triggerContentTarget.innerText = checkedInputs.map((input) => this.inputContent(input)).join(", ")
|
|
62
67
|
}
|
|
63
68
|
}
|
|
64
69
|
|
|
65
|
-
|
|
70
|
+
togglePopover(event) {
|
|
66
71
|
event.preventDefault()
|
|
67
72
|
|
|
73
|
+
if (this.triggerTarget.ariaExpanded === "true") {
|
|
74
|
+
this.closePopover()
|
|
75
|
+
} else {
|
|
76
|
+
this.openPopover(event)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
openPopover(event) {
|
|
81
|
+
if (event) event.preventDefault()
|
|
82
|
+
|
|
68
83
|
this.updatePopoverPosition()
|
|
69
84
|
this.updatePopoverWidth()
|
|
70
85
|
this.triggerTarget.ariaExpanded = "true"
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Views::Docs::Combobox < Views::Base
|
|
4
|
+
@@code_example = nil
|
|
5
|
+
|
|
6
|
+
def view_template
|
|
7
|
+
component = "Combobox"
|
|
8
|
+
div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
|
|
9
|
+
render Docs::Header.new(title: component, description: "Autocomplete input and command palette with a list of suggestions.")
|
|
10
|
+
|
|
11
|
+
Heading(level: 2) { "Usage" }
|
|
12
|
+
|
|
13
|
+
render Docs::VisualCodeExample.new(title: "Single option", context: self) do
|
|
14
|
+
<<~RUBY
|
|
15
|
+
div class: "w-96" do
|
|
16
|
+
Combobox do
|
|
17
|
+
ComboboxTrigger placeholder: "Pick value"
|
|
18
|
+
|
|
19
|
+
ComboboxPopover do
|
|
20
|
+
ComboboxSearchInput(placeholder: "Pick value or type anything")
|
|
21
|
+
|
|
22
|
+
ComboboxList do
|
|
23
|
+
ComboboxEmptyState { "No result" }
|
|
24
|
+
|
|
25
|
+
ComboboxListGroup(label: "Fruits") do
|
|
26
|
+
ComboboxItem do
|
|
27
|
+
ComboboxRadio(name: "food", value: "apple")
|
|
28
|
+
span { "Apple" }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
ComboboxItem do
|
|
32
|
+
ComboboxRadio(name: "food", value: "banana")
|
|
33
|
+
span { "Banana" }
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
ComboboxListGroup(label: "Vegetable") do
|
|
38
|
+
ComboboxItem do
|
|
39
|
+
ComboboxRadio(name: "food", value: "brocoli")
|
|
40
|
+
span { "Broccoli" }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
ComboboxItem do
|
|
44
|
+
ComboboxRadio(name: "food", value: "carrot")
|
|
45
|
+
span { "Carrot" }
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
ComboboxListGroup(label: "Others") do
|
|
50
|
+
ComboboxItem do
|
|
51
|
+
ComboboxRadio(name: "food", value: "chocolate")
|
|
52
|
+
span { "Chocolate" }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
ComboboxItem do
|
|
56
|
+
ComboboxRadio(name: "food", value: "milk")
|
|
57
|
+
span { "Milk" }
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
RUBY
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
render Docs::VisualCodeExample.new(title: "Multiple options", context: self) do
|
|
68
|
+
<<~RUBY
|
|
69
|
+
div class: "w-96" do
|
|
70
|
+
Combobox term: "things" do
|
|
71
|
+
ComboboxTrigger placeholder: "Pick value"
|
|
72
|
+
|
|
73
|
+
ComboboxPopover do
|
|
74
|
+
ComboboxSearchInput(placeholder: "Pick value or type anything")
|
|
75
|
+
|
|
76
|
+
ComboboxList do
|
|
77
|
+
ComboboxEmptyState { "No result" }
|
|
78
|
+
|
|
79
|
+
ComboboxItem(class: "mt-3") do
|
|
80
|
+
ComboboxToggleAllCheckbox(name: "all", value: "all")
|
|
81
|
+
span { "Select all" }
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
ComboboxListGroup label: "Fruits" do
|
|
85
|
+
ComboboxItem do
|
|
86
|
+
ComboboxCheckbox(name: "food", value: "apple")
|
|
87
|
+
span { "Apple" }
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
ComboboxItem do
|
|
91
|
+
ComboboxCheckbox(name: "food", value: "banana")
|
|
92
|
+
span { "Banana" }
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
ComboboxListGroup label: "Vegetable" do
|
|
97
|
+
ComboboxItem do
|
|
98
|
+
ComboboxCheckbox(name: "food", value: "brocoli")
|
|
99
|
+
span { "Broccoli" }
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
ComboboxItem do
|
|
103
|
+
ComboboxCheckbox(name: "food", value: "carrot")
|
|
104
|
+
span { "Carrot" }
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
ComboboxListGroup label: "Others" do
|
|
109
|
+
ComboboxItem do
|
|
110
|
+
ComboboxCheckbox(name: "food", value: "chocolate")
|
|
111
|
+
span { "Chocolate" }
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
ComboboxItem do
|
|
115
|
+
ComboboxCheckbox(name: "food", value: "milk")
|
|
116
|
+
span { "Milk" }
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
RUBY
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
render Docs::VisualCodeExample.new(title: "Disabled", context: self) do
|
|
127
|
+
<<~RUBY
|
|
128
|
+
div(class: "w-96") do
|
|
129
|
+
Combobox do
|
|
130
|
+
ComboboxTrigger(disabled: true, placeholder: "Pick value")
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
RUBY
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
render Docs::VisualCodeExample.new(title: "Aria Disabled", context: self) do
|
|
137
|
+
<<~RUBY
|
|
138
|
+
div(class: "w-96") do
|
|
139
|
+
Combobox do
|
|
140
|
+
ComboboxTrigger(aria: {disabled: "true"}, placeholder: "Pick value")
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
RUBY
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
render Components::ComponentSetup::Tabs.new(component_name: "Combobox")
|
|
147
|
+
|
|
148
|
+
render Docs::ComponentsTable.new(component_files("Combobox"))
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
@@ -13,7 +13,8 @@ module RubyUI
|
|
|
13
13
|
class: [
|
|
14
14
|
"flex flex-row w-full text-wrap [&>span,&>div]:truncate gap-2 items-center rounded-sm px-2 py-1 text-sm outline-none cursor-pointer",
|
|
15
15
|
"select-none has-[:checked]:bg-accent hover:bg-accent p-2",
|
|
16
|
-
"[&>svg]:pointer-events-none [&>svg]:size-4 [&>svg]:shrink-0 aria-[current=true]:bg-accent aria-[current=true]:ring aria-[current=true]:ring-offset-2"
|
|
16
|
+
"[&>svg]:pointer-events-none [&>svg]:size-4 [&>svg]:shrink-0 aria-[current=true]:bg-accent aria-[current=true]:ring aria-[current=true]:ring-offset-2",
|
|
17
|
+
"has-disabled:opacity-50 has-disabled:cursor-not-allowed"
|
|
17
18
|
],
|
|
18
19
|
role: "option",
|
|
19
20
|
data: {
|
|
@@ -17,10 +17,11 @@ module RubyUI
|
|
|
17
17
|
data: {
|
|
18
18
|
ruby_ui__combobox_target: "popover",
|
|
19
19
|
action: %w[
|
|
20
|
+
toggle->ruby-ui--combobox#handlePopoverToggle
|
|
20
21
|
keydown.down->ruby-ui--combobox#keyDownPressed
|
|
21
22
|
keydown.up->ruby-ui--combobox#keyUpPressed
|
|
22
23
|
keydown.enter->ruby-ui--combobox#keyEnterPressed
|
|
23
|
-
keydown.esc->ruby-ui--combobox#
|
|
24
|
+
keydown.esc->ruby-ui--combobox#closePopover:prevent
|
|
24
25
|
resize@window->ruby-ui--combobox#updatePopoverWidth
|
|
25
26
|
]
|
|
26
27
|
}
|
|
@@ -10,7 +10,14 @@ module RubyUI
|
|
|
10
10
|
|
|
11
11
|
def default_attrs
|
|
12
12
|
{
|
|
13
|
-
class:
|
|
13
|
+
class: [
|
|
14
|
+
"aspect-square h-4 w-4 rounded-full border border-primary accent-primary text-primary shadow",
|
|
15
|
+
"focus:outline-none",
|
|
16
|
+
"focus-visible:ring-1 focus-visible:ring-ring",
|
|
17
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
18
|
+
"checked:bg-primary checked:text-primary-foreground",
|
|
19
|
+
"aria-disabled:cursor-not-allowed aria-disabled:opacity-50 aria-disabled:pointer-events-none"
|
|
20
|
+
],
|
|
14
21
|
data: {
|
|
15
22
|
ruby_ui__combobox_target: "input",
|
|
16
23
|
ruby_ui__form_field_target: "input",
|
|
@@ -19,16 +19,22 @@ module RubyUI
|
|
|
19
19
|
def default_attrs
|
|
20
20
|
{
|
|
21
21
|
type: "search",
|
|
22
|
-
class: "flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none border-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
|
23
22
|
role: "searchbox",
|
|
23
|
+
autocorrect: "off",
|
|
24
|
+
autocomplete: "off",
|
|
25
|
+
spellcheck: "false",
|
|
24
26
|
placeholder: @placeholder,
|
|
27
|
+
class: [
|
|
28
|
+
"flex h-9 w-full rounded-md bg-transparent py-3 text-sm outline-none border-none",
|
|
29
|
+
"focus:ring-0",
|
|
30
|
+
"placeholder:text-muted-foreground",
|
|
31
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
32
|
+
"aria-disabled:cursor-not-allowed aria-disabled:opacity-50 aria-disabled:pointer-events-none"
|
|
33
|
+
],
|
|
25
34
|
data: {
|
|
26
35
|
ruby_ui__combobox_target: "searchInput",
|
|
27
36
|
action: "keyup->ruby-ui--combobox#filterItems search->ruby-ui--combobox#filterItems"
|
|
28
|
-
}
|
|
29
|
-
autocomplete: "off",
|
|
30
|
-
autocorrect: "off",
|
|
31
|
-
spellcheck: "false"
|
|
37
|
+
}
|
|
32
38
|
}
|
|
33
39
|
end
|
|
34
40
|
|
|
@@ -12,8 +12,10 @@ module RubyUI
|
|
|
12
12
|
{
|
|
13
13
|
class: [
|
|
14
14
|
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background accent-primary",
|
|
15
|
-
"
|
|
16
|
-
"
|
|
15
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
16
|
+
"checked:bg-primary checked:text-primary-foreground",
|
|
17
|
+
"aria-disabled:cursor-not-allowed aria-disabled:opacity-50 aria-disabled:pointer-events-none",
|
|
18
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
|
17
19
|
],
|
|
18
20
|
data: {
|
|
19
21
|
ruby_ui__combobox_target: "toggleAll",
|