ruby_ui 1.0.0.pre.alpha.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (166) hide show
  1. checksums.yaml +7 -0
  2. data/lib/generators/rbui/base_generator.rb +17 -0
  3. data/lib/generators/rbui/component_generator.rb +137 -0
  4. data/lib/generators/rbui/install/install_generator.rb +194 -0
  5. data/lib/rbui/accordion/accordion.rb +17 -0
  6. data/lib/rbui/accordion/accordion_content.rb +21 -0
  7. data/lib/rbui/accordion/accordion_default_content.rb +17 -0
  8. data/lib/rbui/accordion/accordion_default_trigger.rb +19 -0
  9. data/lib/rbui/accordion/accordion_icon.rb +38 -0
  10. data/lib/rbui/accordion/accordion_item.rb +28 -0
  11. data/lib/rbui/accordion/accordion_trigger.rb +16 -0
  12. data/lib/rbui/alert/alert.rb +36 -0
  13. data/lib/rbui/alert/alert_description.rb +17 -0
  14. data/lib/rbui/alert/alert_title.rb +17 -0
  15. data/lib/rbui/alert_dialog/alert_dialog.rb +26 -0
  16. data/lib/rbui/alert_dialog/alert_dialog_action.rb +17 -0
  17. data/lib/rbui/alert_dialog/alert_dialog_cancel.rb +21 -0
  18. data/lib/rbui/alert_dialog/alert_dialog_content.rb +45 -0
  19. data/lib/rbui/alert_dialog/alert_dialog_description.rb +17 -0
  20. data/lib/rbui/alert_dialog/alert_dialog_footer.rb +17 -0
  21. data/lib/rbui/alert_dialog/alert_dialog_header.rb +17 -0
  22. data/lib/rbui/alert_dialog/alert_dialog_title.rb +17 -0
  23. data/lib/rbui/alert_dialog/alert_dialog_trigger.rb +18 -0
  24. data/lib/rbui/aspect_ratio/aspect_ratio.rb +33 -0
  25. data/lib/rbui/avatar/avatar.rb +31 -0
  26. data/lib/rbui/avatar/avatar_fallback.rb +17 -0
  27. data/lib/rbui/avatar/avatar_image.rb +26 -0
  28. data/lib/rbui/badge/badge.rb +60 -0
  29. data/lib/rbui/base.rb +29 -0
  30. data/lib/rbui/button/button.rb +97 -0
  31. data/lib/rbui/calendar/calendar.rb +39 -0
  32. data/lib/rbui/calendar/calendar_body.rb +19 -0
  33. data/lib/rbui/calendar/calendar_days.rb +104 -0
  34. data/lib/rbui/calendar/calendar_header.rb +17 -0
  35. data/lib/rbui/calendar/calendar_next.rb +43 -0
  36. data/lib/rbui/calendar/calendar_prev.rb +43 -0
  37. data/lib/rbui/calendar/calendar_title.rb +27 -0
  38. data/lib/rbui/calendar/calendar_weekdays.rb +33 -0
  39. data/lib/rbui/card/card.rb +17 -0
  40. data/lib/rbui/card/card_content.rb +17 -0
  41. data/lib/rbui/card/card_description.rb +17 -0
  42. data/lib/rbui/card/card_footer.rb +17 -0
  43. data/lib/rbui/card/card_header.rb +17 -0
  44. data/lib/rbui/card/card_title.rb +17 -0
  45. data/lib/rbui/chart/chart.rb +23 -0
  46. data/lib/rbui/checkbox/checkbox.rb +23 -0
  47. data/lib/rbui/checkbox/checkbox_group.rb +20 -0
  48. data/lib/rbui/clipboard/clipboard.rb +42 -0
  49. data/lib/rbui/clipboard/clipboard_popover.rb +40 -0
  50. data/lib/rbui/clipboard/clipboard_source.rb +19 -0
  51. data/lib/rbui/clipboard/clipboard_trigger.rb +20 -0
  52. data/lib/rbui/codeblock/codeblock.rb +105 -0
  53. data/lib/rbui/collapsible/collapsible.rb +25 -0
  54. data/lib/rbui/collapsible/collapsible_content.rb +18 -0
  55. data/lib/rbui/collapsible/collapsible_trigger.rb +19 -0
  56. data/lib/rbui/combobox/combobox.rb +24 -0
  57. data/lib/rbui/combobox/combobox_content.rb +31 -0
  58. data/lib/rbui/combobox/combobox_empty.rb +21 -0
  59. data/lib/rbui/combobox/combobox_group.rb +38 -0
  60. data/lib/rbui/combobox/combobox_input.rb +22 -0
  61. data/lib/rbui/combobox/combobox_item.rb +53 -0
  62. data/lib/rbui/combobox/combobox_list.rb +29 -0
  63. data/lib/rbui/combobox/combobox_search_input.rb +56 -0
  64. data/lib/rbui/combobox/combobox_separator.rb +15 -0
  65. data/lib/rbui/combobox/combobox_trigger.rb +52 -0
  66. data/lib/rbui/combobox/combobox_value.rb +27 -0
  67. data/lib/rbui/command/command.rb +9 -0
  68. data/lib/rbui/command/command_dialog.rb +17 -0
  69. data/lib/rbui/command/command_dialog_content.rb +48 -0
  70. data/lib/rbui/command/command_dialog_trigger.rb +29 -0
  71. data/lib/rbui/command/command_empty.rb +19 -0
  72. data/lib/rbui/command/command_group.rb +40 -0
  73. data/lib/rbui/command/command_input.rb +56 -0
  74. data/lib/rbui/command/command_item.rb +32 -0
  75. data/lib/rbui/command/command_list.rb +17 -0
  76. data/lib/rbui/context_menu/context_menu.rb +26 -0
  77. data/lib/rbui/context_menu/context_menu_content.rb +25 -0
  78. data/lib/rbui/context_menu/context_menu_item.rb +66 -0
  79. data/lib/rbui/context_menu/context_menu_label.rb +24 -0
  80. data/lib/rbui/context_menu/context_menu_separator.rb +19 -0
  81. data/lib/rbui/context_menu/context_menu_trigger.rb +20 -0
  82. data/lib/rbui/dialog/dialog.rb +25 -0
  83. data/lib/rbui/dialog/dialog_content.rb +78 -0
  84. data/lib/rbui/dialog/dialog_description.rb +17 -0
  85. data/lib/rbui/dialog/dialog_footer.rb +17 -0
  86. data/lib/rbui/dialog/dialog_header.rb +17 -0
  87. data/lib/rbui/dialog/dialog_middle.rb +17 -0
  88. data/lib/rbui/dialog/dialog_title.rb +17 -0
  89. data/lib/rbui/dialog/dialog_trigger.rb +20 -0
  90. data/lib/rbui/dropdown_menu/dropdown_menu.rb +26 -0
  91. data/lib/rbui/dropdown_menu/dropdown_menu_content.rb +22 -0
  92. data/lib/rbui/dropdown_menu/dropdown_menu_item.rb +28 -0
  93. data/lib/rbui/dropdown_menu/dropdown_menu_label.rb +17 -0
  94. data/lib/rbui/dropdown_menu/dropdown_menu_separator.rb +19 -0
  95. data/lib/rbui/dropdown_menu/dropdown_menu_trigger.rb +18 -0
  96. data/lib/rbui/form/form.rb +15 -0
  97. data/lib/rbui/form/form_field.rb +20 -0
  98. data/lib/rbui/form/form_field_error.rb +20 -0
  99. data/lib/rbui/form/form_field_hint.rb +15 -0
  100. data/lib/rbui/form/form_field_label.rb +15 -0
  101. data/lib/rbui/hover_card/hover_card.rb +27 -0
  102. data/lib/rbui/hover_card/hover_card_content.rb +22 -0
  103. data/lib/rbui/hover_card/hover_card_trigger.rb +20 -0
  104. data/lib/rbui/input/input.rb +26 -0
  105. data/lib/rbui/link/link.rb +97 -0
  106. data/lib/rbui/pagination/pagination.rb +19 -0
  107. data/lib/rbui/pagination/pagination_content.rb +17 -0
  108. data/lib/rbui/pagination/pagination_ellipsis.rb +42 -0
  109. data/lib/rbui/pagination/pagination_item.rb +28 -0
  110. data/lib/rbui/popover/popover.rb +26 -0
  111. data/lib/rbui/popover/popover_content.rb +27 -0
  112. data/lib/rbui/popover/popover_trigger.rb +20 -0
  113. data/lib/rbui/radio_button/radio_button.rb +22 -0
  114. data/lib/rbui/railtie.rb +52 -0
  115. data/lib/rbui/select/select.rb +23 -0
  116. data/lib/rbui/select/select_content.rb +32 -0
  117. data/lib/rbui/select/select_group.rb +15 -0
  118. data/lib/rbui/select/select_input.rb +22 -0
  119. data/lib/rbui/select/select_item.rb +52 -0
  120. data/lib/rbui/select/select_label.rb +17 -0
  121. data/lib/rbui/select/select_trigger.rb +54 -0
  122. data/lib/rbui/select/select_value.rb +27 -0
  123. data/lib/rbui/sheet/sheet.rb +17 -0
  124. data/lib/rbui/sheet/sheet_content.rb +77 -0
  125. data/lib/rbui/sheet/sheet_description.rb +17 -0
  126. data/lib/rbui/sheet/sheet_footer.rb +17 -0
  127. data/lib/rbui/sheet/sheet_header.rb +17 -0
  128. data/lib/rbui/sheet/sheet_middle.rb +17 -0
  129. data/lib/rbui/sheet/sheet_title.rb +17 -0
  130. data/lib/rbui/sheet/sheet_trigger.rb +17 -0
  131. data/lib/rbui/shortcut_key/shortcut_key.rb +17 -0
  132. data/lib/rbui/table/table.rb +19 -0
  133. data/lib/rbui/table/table_body.rb +17 -0
  134. data/lib/rbui/table/table_caption.rb +17 -0
  135. data/lib/rbui/table/table_cell.rb +17 -0
  136. data/lib/rbui/table/table_footer.rb +17 -0
  137. data/lib/rbui/table/table_head.rb +17 -0
  138. data/lib/rbui/table/table_header.rb +17 -0
  139. data/lib/rbui/table/table_row.rb +17 -0
  140. data/lib/rbui/tabs/tabs.rb +25 -0
  141. data/lib/rbui/tabs/tabs_content.rb +26 -0
  142. data/lib/rbui/tabs/tabs_list.rb +17 -0
  143. data/lib/rbui/tabs/tabs_trigger.rb +28 -0
  144. data/lib/rbui/textarea/textarea.rb +26 -0
  145. data/lib/rbui/theme_toggle/theme_toggle.rb +41 -0
  146. data/lib/rbui/tooltip/tooltip.rb +26 -0
  147. data/lib/rbui/tooltip/tooltip_content.rb +26 -0
  148. data/lib/rbui/tooltip/tooltip_trigger.rb +19 -0
  149. data/lib/rbui/typography/typography_blockquote.rb +17 -0
  150. data/lib/rbui/typography/typography_h1.rb +17 -0
  151. data/lib/rbui/typography/typography_h2.rb +17 -0
  152. data/lib/rbui/typography/typography_h3.rb +17 -0
  153. data/lib/rbui/typography/typography_h4.rb +17 -0
  154. data/lib/rbui/typography/typography_inline_code.rb +17 -0
  155. data/lib/rbui/typography/typography_inline_link.rb +22 -0
  156. data/lib/rbui/typography/typography_large.rb +17 -0
  157. data/lib/rbui/typography/typography_lead.rb +17 -0
  158. data/lib/rbui/typography/typography_list.rb +47 -0
  159. data/lib/rbui/typography/typography_list_item.rb +17 -0
  160. data/lib/rbui/typography/typography_muted.rb +17 -0
  161. data/lib/rbui/typography/typography_p.rb +17 -0
  162. data/lib/rbui/typography/typography_small.rb +17 -0
  163. data/lib/rbui/version.rb +5 -0
  164. data/lib/rbui.rb +57 -0
  165. data/lib/ruby_ui.rb +1 -0
  166. metadata +291 -0
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class ComboboxGroup < Base
5
+ def initialize(heading: nil, **attrs)
6
+ @heading = heading
7
+ super(**attrs)
8
+ end
9
+
10
+ def view_template(&block)
11
+ div(**attrs) do
12
+ render_header if @heading
13
+ render_items(&block)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def render_header
20
+ div(group_heading: @heading, class: "px-2 py-1.5 text-xs font-medium text-muted-foreground") { @heading }
21
+ end
22
+
23
+ def render_items(&)
24
+ div(group_items: "", role: "group", &)
25
+ end
26
+
27
+ def default_attrs
28
+ {
29
+ class: "overflow-hidden p-1 text-foreground",
30
+ role: "presentation",
31
+ data: {
32
+ value: @heading,
33
+ rbui__combobox_content_target: "group"
34
+ }
35
+ }
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class ComboboxInput < Base
5
+ def view_template
6
+ input(**attrs)
7
+ end
8
+
9
+ private
10
+
11
+ def default_attrs
12
+ {
13
+ class: "hidden",
14
+ data: {
15
+ rbui__combobox_target: "input",
16
+ rbui__form_field_target: "input",
17
+ action: "change->rbui--form-field#onChange invalid->rbui--form-field#onInvalid"
18
+ }
19
+ }
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class ComboboxItem < Base
5
+ def initialize(value: nil, **attrs)
6
+ @value = value
7
+ super(**attrs)
8
+ end
9
+
10
+ def view_template(&block)
11
+ div(**attrs) do
12
+ div(class: "invisible group-aria-selected:visible") { icon }
13
+ block.call
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def icon
20
+ svg(
21
+ xmlns: "http://www.w3.org/2000/svg",
22
+ viewbox: "0 0 24 24",
23
+ fill: "none",
24
+ stroke: "currentColor",
25
+ class: "mr-2 h-4 w-4",
26
+ stroke_width: "2",
27
+ stroke_linecap: "round",
28
+ stroke_linejoin: "round"
29
+ ) do |s|
30
+ s.path(
31
+ d: "M20 6 9 17l-5-5"
32
+ )
33
+ end
34
+ end
35
+
36
+ def default_attrs
37
+ {
38
+ role: "option",
39
+ tabindex: "0",
40
+ class:
41
+ "combobox-item group relative flex cursor-pointer select-none items-center gap-x-2 rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground aria-[current]:bg-accent aria-[current]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
42
+ data: {
43
+ value: @value,
44
+ rbui__combobox_target: "item",
45
+ rbui__combobox_content_target: "item",
46
+ controller: "rbui--combobox-item",
47
+ action: "click->rbui--combobox#onItemSelected"
48
+ },
49
+ aria_selected: "false"
50
+ }
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "securerandom"
4
+
5
+ module RBUI
6
+ class ComboboxList < Base
7
+ def initialize(**attrs)
8
+ @id = "list#{SecureRandom.hex(4)}"
9
+ super
10
+ end
11
+
12
+ def view_template(&)
13
+ div(**attrs, &)
14
+ end
15
+
16
+ private
17
+
18
+ def default_attrs
19
+ {
20
+ id: @id,
21
+ data: {
22
+ rbui__combobox_target: "list"
23
+ },
24
+ role: "listbox",
25
+ tabindex: "-1"
26
+ }
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class ComboboxSearchInput < Base
5
+ def initialize(placeholder:, **attrs)
6
+ @placeholder = placeholder
7
+ super(**attrs)
8
+ end
9
+
10
+ def view_template
11
+ input_container do
12
+ search_icon
13
+ input(**attrs)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def search_icon
20
+ svg(
21
+ xmlns: "http://www.w3.org/2000/svg",
22
+ viewbox: "0 0 24 24",
23
+ fill: "none",
24
+ stroke: "currentColor",
25
+ class: "mr-2 h-4 w-4 shrink-0 opacity-50",
26
+ stroke_width: "2",
27
+ stroke_linecap: "round",
28
+ stroke_linejoin: "round"
29
+ ) do |s|
30
+ s.circle(cx: "11", cy: "11", r: "8")
31
+ s.path(
32
+ d: "m21 21-4.3-4.3"
33
+ )
34
+ end
35
+ end
36
+
37
+ def input_container(&)
38
+ div(class: "flex items-center border-b px-3", &)
39
+ end
40
+
41
+ def default_attrs
42
+ {
43
+ class:
44
+ "flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
45
+ placeholder: @placeholder,
46
+ data: {
47
+ action: "input->rbui--combobox#onSearchInput",
48
+ rbui__combobox_target: "search"
49
+ },
50
+ autocomplete: "off",
51
+ autocorrect: "off",
52
+ spellcheck: false
53
+ }
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class ComboboxSeparator < Base
5
+ def view_template(&)
6
+ div(**attrs, &)
7
+ end
8
+
9
+ private
10
+
11
+ def default_attrs
12
+ {class: "-mx-1 h-px bg-border"}
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class ComboboxTrigger < Base
5
+ def view_template(&block)
6
+ button(**attrs) do
7
+ block&.call
8
+ icon
9
+ end
10
+ end
11
+
12
+ private
13
+
14
+ def icon
15
+ svg(
16
+ xmlns: "http://www.w3.org/2000/svg",
17
+ viewbox: "0 0 24 24",
18
+ fill: "none",
19
+ stroke: "currentColor",
20
+ class: "ml-2 h-4 w-4 shrink-0 opacity-50",
21
+ stroke_width: "2",
22
+ stroke_linecap: "round",
23
+ stroke_linejoin: "round"
24
+ ) do |s|
25
+ s.path(
26
+ d: "m7 15 5 5 5-5"
27
+ )
28
+ s.path(
29
+ d: "m7 9 5-5 5 5"
30
+ )
31
+ end
32
+ end
33
+
34
+ def default_attrs
35
+ {
36
+ data: {
37
+ action: "rbui--combobox#onTriggerClick",
38
+ rbui__combobox_target: "trigger"
39
+ },
40
+ type: "button",
41
+ role: "combobox",
42
+ aria: {
43
+ expanded: "false",
44
+ haspopup: "listbox",
45
+ autocomplete: "none",
46
+ activedescendant: true
47
+ },
48
+ 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 w-[200px] justify-between"
49
+ }
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class ComboboxValue < Base
5
+ def initialize(placeholder: nil, **attrs)
6
+ @placeholder = placeholder
7
+ super(**attrs)
8
+ end
9
+
10
+ def view_template(&block)
11
+ span(**attrs) do
12
+ block ? block.call : @placeholder
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def default_attrs
19
+ {
20
+ data: {
21
+ rbui__combobox_target: "value"
22
+ },
23
+ class: "pointer-events-none"
24
+ }
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class Command < Base
5
+ def view_template(&)
6
+ div(**attrs, &)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class CommandDialog < Base
5
+ def view_template(&)
6
+ div(**attrs, &)
7
+ end
8
+
9
+ private
10
+
11
+ def default_attrs
12
+ {
13
+ data: {controller: "rbui--command"}
14
+ }
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class CommandDialogContent < Base
5
+ SIZES = {
6
+ xs: "max-w-sm",
7
+ sm: "max-w-md",
8
+ md: "max-w-lg",
9
+ lg: "max-w-2xl",
10
+ xl: "max-w-4xl",
11
+ full: "max-w-full"
12
+ }
13
+
14
+ def initialize(size: :md, **attrs)
15
+ @size = size
16
+ super(**attrs)
17
+ end
18
+
19
+ def view_template(&block)
20
+ template_tag(data: {rbui__command_target: "content"}) do
21
+ div(data: {controller: "rbui--command"}) do
22
+ backdrop
23
+ div(**attrs, &block)
24
+ end
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def default_attrs
31
+ {
32
+ data_state: "open",
33
+ class: tokens(
34
+ "fixed pointer-events-auto left-[50%] top-[50%] z-50 grid w-full translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background 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",
35
+ SIZES[@size]
36
+ )
37
+ }
38
+ end
39
+
40
+ def backdrop
41
+ div(
42
+ data_state: "open",
43
+ data_action: "click->rbui--command#dismiss esc->rbui--command#dismiss",
44
+ class: "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"
45
+ )
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class CommandDialogTrigger < Base
5
+ DEFAULT_KEYBINDINGS = [
6
+ "keydown.ctrl+k@window",
7
+ "keydown.meta+k@window"
8
+ ].freeze
9
+
10
+ def initialize(keybindings: DEFAULT_KEYBINDINGS, **attrs)
11
+ @keybindings = keybindings.map { |kb| "#{kb}->rbui--command#open" }
12
+ super(**attrs)
13
+ end
14
+
15
+ def view_template(&)
16
+ div(**attrs, &)
17
+ end
18
+
19
+ private
20
+
21
+ def default_attrs
22
+ {
23
+ data: {
24
+ action: tokens("click->rbui--command#open", @keybindings.join(" "))
25
+ }
26
+ }
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class CommandEmpty < Base
5
+ def view_template(&)
6
+ div(**attrs, &)
7
+ end
8
+
9
+ private
10
+
11
+ def default_attrs
12
+ {
13
+ class: "py-6 text-center text-sm",
14
+ role: "presentation",
15
+ data: {rbui__command_target: "empty"}
16
+ }
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class CommandGroup < Base
5
+ def initialize(title: nil, **attrs)
6
+ @title = title
7
+ super(**attrs)
8
+ end
9
+
10
+ def view_template(&block)
11
+ div(**attrs) do
12
+ render_header if @title
13
+ render_items(&block)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def render_header
20
+ div(group_heading: @title) do
21
+ @title
22
+ end
23
+ end
24
+
25
+ def render_items(&)
26
+ div(group_items: "", role: "group", &)
27
+ end
28
+
29
+ def default_attrs
30
+ {
31
+ class: "overflow-hidden p-1 text-foreground [&_[group-heading]]:px-2 [&_[group-heading]]:py-1.5 [&_[group-heading]]:text-xs [&_[group-heading]]:font-medium [&_[group-heading]]:text-muted-foreground",
32
+ role: "presentation",
33
+ data: {
34
+ value: @title,
35
+ rbui__command_target: "group"
36
+ }
37
+ }
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class CommandInput < Base
5
+ def initialize(placeholder: "Type a command or search...", **attrs)
6
+ @placeholder = placeholder
7
+ super(**attrs)
8
+ end
9
+
10
+ def view_template
11
+ input_container do
12
+ search_icon
13
+ input(**attrs)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def search_icon
20
+ svg(
21
+ xmlns: "http://www.w3.org/2000/svg",
22
+ viewbox: "0 0 20 20",
23
+ fill: "currentColor",
24
+ class: "w-4 h-4 mr-1.5"
25
+ ) do |s|
26
+ s.path(
27
+ fill_rule: "evenodd",
28
+ d:
29
+ "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",
30
+ clip_rule: "evenodd"
31
+ )
32
+ end
33
+ end
34
+
35
+ def input_container(&)
36
+ div(class: "flex items-center border-b px-3", &)
37
+ end
38
+
39
+ def default_attrs
40
+ {
41
+ class: "flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
42
+ placeholder: @placeholder,
43
+ data_action: "input->rbui--command#filter keydown.down->rbui--command#handleKeydown keydown.up->rbui--command#handleKeydown keydown.enter->rbui--command#handleKeydown keydown.esc->rbui--command#dismiss",
44
+ data_rbui__command_target: "input",
45
+ autocomplete: "off",
46
+ autocorrect: "off",
47
+ spellcheck: false,
48
+ autofocus: true,
49
+ aria_autocomplete: "list",
50
+ role: "combobox",
51
+ aria_expanded: true,
52
+ value: ""
53
+ }
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class CommandItem < Base
5
+ def initialize(value:, text: "", href: "#", **attrs)
6
+ @value = value
7
+ @text = text
8
+ @href = href
9
+ super(**attrs)
10
+ end
11
+
12
+ def view_template(&)
13
+ a(**attrs, &)
14
+ end
15
+
16
+ private
17
+
18
+ def default_attrs
19
+ {
20
+ class: "relative flex cursor-pointer select-none items-center gap-x-2 rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
21
+ href: @href,
22
+ role: "option",
23
+ data: {
24
+ rbui__command_target: "item",
25
+ value: @value,
26
+ text: @text
27
+ }
28
+ # aria_selected: "true", # Toggles aria-selected="true" on keydown
29
+ }
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class CommandList < Base
5
+ def view_template(&)
6
+ div(**attrs, &)
7
+ end
8
+
9
+ private
10
+
11
+ def default_attrs
12
+ {
13
+ class: "divide-y divide-border"
14
+ }
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class ContextMenu < Base
5
+ def initialize(options: {}, **attrs)
6
+ @options = options
7
+ @options[:trigger] ||= "manual"
8
+ super(**attrs)
9
+ end
10
+
11
+ def view_template(&)
12
+ div(**attrs, &)
13
+ end
14
+
15
+ private
16
+
17
+ def default_attrs
18
+ {
19
+ data: {
20
+ controller: "rbui--context-menu",
21
+ popover_options_value: @options.to_json
22
+ }
23
+ }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class ContextMenuContent < Base
5
+ def view_template(&block)
6
+ template_tag(data: {rbui__context_menu_target: "content"}) do
7
+ div(**attrs, &block)
8
+ end
9
+ end
10
+
11
+ private
12
+
13
+ def default_attrs
14
+ {
15
+ role: "menu",
16
+ aria_orientation: "vertical",
17
+ data_state: "open",
18
+ class:
19
+ "z-50 min-w-[8rem] outline-none pointer-events-auto 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",
20
+ tabindex: "-1",
21
+ data_orientation: "vertical"
22
+ }
23
+ end
24
+ end
25
+ end