ruby_ui 1.0.0.pre.alpha.4

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 (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