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,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class AlertDialogContent < Base
5
+ def view_template(&block)
6
+ template_tag(**attrs) do
7
+ div(data: {controller: "rbui--alert-dialog"}) do
8
+ background
9
+ container(&block)
10
+ end
11
+ end
12
+ end
13
+
14
+ def background
15
+ div(
16
+ data_state: "open",
17
+ class:
18
+ "fixed inset-0 z-50 bg-black/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",
19
+ style: "pointer-events:auto",
20
+ data_aria_hidden: "true",
21
+ aria_hidden: "true"
22
+ )
23
+ end
24
+
25
+ def container(&)
26
+ div(
27
+ role: "alertdialog",
28
+ data_state: "open",
29
+ class: "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg 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",
30
+ style: "pointer-events:auto",
31
+ &
32
+ )
33
+ end
34
+
35
+ private
36
+
37
+ def default_attrs
38
+ {
39
+ data: {
40
+ rbui__alert_dialog_target: "content"
41
+ }
42
+ }
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class AlertDialogDescription < Base
5
+ def view_template(&)
6
+ p(**attrs, &)
7
+ end
8
+
9
+ private
10
+
11
+ def default_attrs
12
+ {
13
+ class: "text-sm text-muted-foreground"
14
+ }
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class AlertDialogFooter < Base
5
+ def view_template(&)
6
+ div(**attrs, &)
7
+ end
8
+
9
+ private
10
+
11
+ def default_attrs
12
+ {
13
+ class: "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2"
14
+ }
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class AlertDialogHeader < Base
5
+ def view_template(&)
6
+ div(**attrs, &)
7
+ end
8
+
9
+ private
10
+
11
+ def default_attrs
12
+ {
13
+ class: "flex flex-col space-y-2 text-center sm:text-left"
14
+ }
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class AlertDialogTitle < Base
5
+ def view_template(&)
6
+ h2(**attrs, &)
7
+ end
8
+
9
+ private
10
+
11
+ def default_attrs
12
+ {
13
+ class: "text-lg font-semibold"
14
+ }
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class AlertDialogTrigger < Base
5
+ def view_template(&)
6
+ div(**attrs, &)
7
+ end
8
+
9
+ private
10
+
11
+ def default_attrs
12
+ {
13
+ data: {action: "click->rbui--alert-dialog#open"},
14
+ class: "inline-block"
15
+ }
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class AspectRatio < Base
5
+ def initialize(aspect_ratio: "16/9", **attrs)
6
+ raise "aspect_ratio must be in the format of a string with a slash in the middle (eg. '16/9', '1/1')" unless aspect_ratio.is_a?(String) && aspect_ratio.include?("/")
7
+
8
+ @aspect_ratio = aspect_ratio
9
+ super(**attrs)
10
+ end
11
+
12
+ def view_template(&block)
13
+ div(
14
+ class: "relative w-full",
15
+ style: "padding-bottom: #{padding_bottom}%;"
16
+ ) do
17
+ div(**attrs, &block)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def padding_bottom
24
+ @aspect_ratio.split("/").map(&:to_i).reverse.reduce(&:fdiv) * 100
25
+ end
26
+
27
+ def default_attrs
28
+ {
29
+ class: "bg-muted absolute inset-0 [&>img]:object-cover [&>img]:absolute [&>img]:h-full [&>img]:w-full [&>img]:inset-0 [&>img]:text-transparent"
30
+ }
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class Avatar < Base
5
+ SIZES = {
6
+ xs: "h-4 w-4 text-[0.5rem]",
7
+ sm: "h-6 w-6 text-xs",
8
+ md: "h-10 w-10 text-base",
9
+ lg: "h-14 w-14 text-xl",
10
+ xl: "h-20 w-20 text-3xl"
11
+ }
12
+
13
+ def initialize(size: :md, **attrs)
14
+ @size = size
15
+ @size_classes = SIZES[@size]
16
+ super(**attrs)
17
+ end
18
+
19
+ def view_template(&)
20
+ span(**attrs, &)
21
+ end
22
+
23
+ private
24
+
25
+ def default_attrs
26
+ {
27
+ class: tokens("relative flex shrink-0 overflow-hidden rounded-full", @size_classes)
28
+ }
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class AvatarFallback < Base
5
+ def view_template(&)
6
+ span(**attrs, &)
7
+ end
8
+
9
+ private
10
+
11
+ def default_attrs
12
+ {
13
+ class: "flex h-full w-full items-center justify-center rounded-full bg-muted"
14
+ }
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class AvatarImage < Base
5
+ def initialize(src:, alt: "", **attrs)
6
+ @src = src
7
+ @alt = alt
8
+ super(**attrs)
9
+ end
10
+
11
+ def view_template
12
+ img(**attrs)
13
+ end
14
+
15
+ private
16
+
17
+ def default_attrs
18
+ {
19
+ loading: "lazy",
20
+ class: "aspect-square h-full w-full",
21
+ alt: @alt,
22
+ src: @src
23
+ }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class Badge < Base
5
+ SIZES = {
6
+ sm: "px-1.5 py-0.5 text-xs",
7
+ md: "px-2 py-1 text-xs",
8
+ lg: "px-3 py-1 text-sm"
9
+ }
10
+
11
+ COLORS = {
12
+ primary: "text-primary bg-primary/5 ring-primary/20",
13
+ secondary: "text-secondary bg-secondary/10 ring-secondary/20",
14
+ outline: "text-foreground bg-background ring-border",
15
+ destructive: "text-destructive bg-destructive/10 ring-destructive/20",
16
+ success: "text-success bg-success/10 ring-success/20",
17
+ warning: "text-warning bg-warning/10 ring-warning/20",
18
+ slate: "text-slate-500 bg-slate-500/10 ring-slate-500/20",
19
+ gray: "text-gray-500 bg-gray-500/10 ring-gray-500/20",
20
+ zinc: "text-zinc-500 bg-zinc-500/10 ring-zinc-500/20",
21
+ neutral: "text-neutral-500 bg-neutral-500/10 ring-neutral-500/20",
22
+ stone: "text-stone-500 bg-stone-500/10 ring-stone-500/20",
23
+ red: "text-red-500 bg-red-500/10 ring-red-500/20",
24
+ orange: "text-orange-500 bg-orange-500/10 ring-orange-500/20",
25
+ amber: "text-amber-500 bg-amber-500/10 ring-amber-500/20",
26
+ yellow: "text-yellow-500 bg-yellow-500/10 ring-yellow-500/20",
27
+ lime: "text-lime-500 bg-lime-500/10 ring-lime-500/20",
28
+ green: "text-green-500 bg-green-500/10 ring-green-500/20",
29
+ emerald: "text-emerald-500 bg-emerald-500/10 ring-emerald-500/20",
30
+ teal: "text-teal-500 bg-teal-500/10 ring-teal-500/20",
31
+ cyan: "text-cyan-500 bg-cyan-500/10 ring-cyan-500/20",
32
+ sky: "text-sky-500 bg-sky-500/10 ring-sky-500/20",
33
+ blue: "text-blue-500 bg-blue-500/10 ring-blue-500/20",
34
+ indigo: "text-indigo-500 bg-indigo-500/10 ring-indigo-500/20",
35
+ violet: "text-violet-500 bg-violet-500/10 ring-violet-500/20",
36
+ purple: "text-purple-500 bg-purple-500/10 ring-purple-500/20",
37
+ fuchsia: "text-fuchsia-500 bg-fuchsia-500/10 ring-fuchsia-500/20",
38
+ pink: "text-pink-500 bg-pink-500/10 ring-pink-500/20",
39
+ rose: "text-rose-500 bg-rose-500/10 ring-rose-500/20"
40
+ }
41
+
42
+ def initialize(variant: :primary, size: :md, **args)
43
+ @variant = variant
44
+ @size = size
45
+ super(**args)
46
+ end
47
+
48
+ def view_template(&)
49
+ span(**attrs, &)
50
+ end
51
+
52
+ private
53
+
54
+ def default_attrs
55
+ {
56
+ class: tokens("inline-flex items-center rounded-md font-medium ring-1 ring-inset", SIZES[@size], COLORS[@variant])
57
+ }
58
+ end
59
+ end
60
+ end
data/lib/rbui/base.rb ADDED
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "tailwind_merge"
4
+
5
+ module RBUI
6
+ class Base < Phlex::HTML
7
+ TAILWIND_MERGER = ::TailwindMerge::Merger.new.freeze unless defined?(TAILWIND_MERGER)
8
+
9
+ attr_reader :attrs
10
+
11
+ def initialize(**user_attrs)
12
+ @attrs = mix(default_attrs, user_attrs)
13
+ @attrs[:class] = TAILWIND_MERGER.merge(@attrs[:class]) if @attrs[:class]
14
+ end
15
+
16
+ if defined?(Rails) && Rails.env.development?
17
+ def before_template
18
+ comment { "Before #{self.class.name}" }
19
+ super
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def default_attrs
26
+ {}
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class Button < Base
5
+ def initialize(type: :button, variant: :primary, size: :md, icon: false, **attrs)
6
+ @type = type
7
+ @variant = variant.to_sym
8
+ @size = size.to_sym
9
+ @icon = icon
10
+ super(**attrs)
11
+ end
12
+
13
+ def view_template(&)
14
+ button(**attrs, &)
15
+ end
16
+
17
+ private
18
+
19
+ def size_classes
20
+ if @icon
21
+ case @size
22
+ when :sm then "h-6 w-6"
23
+ when :md then "h-9 w-9"
24
+ when :lg then "h-10 w-10"
25
+ when :xl then "h-12 w-12"
26
+ end
27
+ else
28
+ case @size
29
+ when :sm then "px-3 py-1.5 h-8 text-xs"
30
+ when :md then "px-4 py-2 h-9 text-sm"
31
+ when :lg then "px-4 py-2 h-10 text-base"
32
+ when :xl then "px-6 py-3 h-12 text-base"
33
+ end
34
+ end
35
+ end
36
+
37
+ def primary_classes
38
+ tokens(
39
+ "whitespace-nowrap inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground shadow hover:bg-primary/90",
40
+ size_classes
41
+ )
42
+ end
43
+
44
+ def link_classes
45
+ tokens(
46
+ "whitespace-nowrap inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 text-primary underline-offset-4 hover:underline",
47
+ size_classes
48
+ )
49
+ end
50
+
51
+ def secondary_classes
52
+ tokens(
53
+ "whitespace-nowrap inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-secondary text-secondary-foreground hover:bg-opacity-80",
54
+ size_classes
55
+ )
56
+ end
57
+
58
+ def destructive_classes
59
+ tokens(
60
+ "whitespace-nowrap inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
61
+ size_classes
62
+ )
63
+ end
64
+
65
+ def outline_classes
66
+ tokens(
67
+ "whitespace-nowrap inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
68
+ size_classes
69
+ )
70
+ end
71
+
72
+ def ghost_classes
73
+ tokens(
74
+ "whitespace-nowrap inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground",
75
+ size_classes
76
+ )
77
+ end
78
+
79
+ def default_classes
80
+ case @variant
81
+ when :primary then primary_classes
82
+ when :link then link_classes
83
+ when :secondary then secondary_classes
84
+ when :destructive then destructive_classes
85
+ when :outline then outline_classes
86
+ when :ghost then ghost_classes
87
+ end
88
+ end
89
+
90
+ def default_attrs
91
+ {
92
+ type: @type,
93
+ class: default_classes
94
+ }
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class Calendar < Base
5
+ def initialize(selected_date: nil, input_id: nil, date_format: "yyyy-MM-dd", **attrs)
6
+ @selected_date = selected_date
7
+ @input_id = input_id
8
+ @date_format = date_format
9
+ super(**attrs)
10
+ end
11
+
12
+ def view_template
13
+ div(**attrs) do
14
+ RBUI.CalendarHeader do
15
+ RBUI.CalendarTitle
16
+ RBUI.CalendarPrev
17
+ RBUI.CalendarNext
18
+ end
19
+ RBUI.CalendarBody # Where the calendar is rendered (Weekdays and Days)
20
+ RBUI.CalendarWeekdays # Template for the weekdays
21
+ RBUI.CalendarDays # Template for the days
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def default_attrs
28
+ {
29
+ class: "p-3 space-y-4",
30
+ data: {
31
+ controller: "rbui--calendar",
32
+ rbui__calendar_selected_date_value: @selected_date&.to_s,
33
+ rbui__calendar_format_value: @date_format,
34
+ rbui__calendar_rbui__calendar_input_outlet: @input_id
35
+ }
36
+ }
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class CalendarBody < Base
5
+ def view_template
6
+ table(**attrs)
7
+ end
8
+
9
+ private
10
+
11
+ def default_attrs
12
+ {
13
+ data: {
14
+ rbui__calendar_target: "calendar"
15
+ }
16
+ }
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class CalendarDays < Base
5
+ BASE_CLASS = "inline-flex items-center justify-center 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 h-8 w-8 p-0 font-normal aria-selected:opacity-100"
6
+
7
+ def view_template
8
+ render_selected_date_template
9
+ render_today_date_template
10
+ render_current_month_date_template
11
+ render_other_month_date_template
12
+ end
13
+
14
+ private
15
+
16
+ def render_selected_date_template
17
+ date_template("selectedDateTemplate") do
18
+ button(
19
+ data_day: "{{day}}",
20
+ data_action: "click->rbui--calendar#selectDay",
21
+ name: "day",
22
+ class:
23
+ tokens(
24
+ BASE_CLASS,
25
+ "bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground"
26
+ ),
27
+ role: "gridcell",
28
+ tabindex: "0",
29
+ type: "button",
30
+ aria_selected: "true"
31
+ ) { "{{dayDate}}" }
32
+ end
33
+ end
34
+
35
+ def render_today_date_template
36
+ date_template("todayDateTemplate") do
37
+ button(
38
+ data_day: "{{day}}",
39
+ data_action: "click->rbui--calendar#selectDay",
40
+ name: "day",
41
+ class:
42
+ tokens(
43
+ BASE_CLASS,
44
+ "bg-accent text-accent-foreground hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground"
45
+ ),
46
+ role: "gridcell",
47
+ tabindex: "-1",
48
+ type: "button"
49
+ ) { "{{dayDate}}" }
50
+ end
51
+ end
52
+
53
+ def render_current_month_date_template
54
+ date_template("currentMonthDateTemplate") do
55
+ button(
56
+ data_day: "{{day}}",
57
+ data_action: "click->rbui--calendar#selectDay",
58
+ name: "day",
59
+ class:
60
+ tokens(
61
+ BASE_CLASS,
62
+ "bg-background text-foreground hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground"
63
+ ),
64
+ role: "gridcell",
65
+ tabindex: "-1",
66
+ type: "button"
67
+ ) { "{{dayDate}}" }
68
+ end
69
+ end
70
+
71
+ def render_other_month_date_template
72
+ date_template("otherMonthDateTemplate") do
73
+ button(
74
+ data_day: "{{day}}",
75
+ data_action: " click->rbui--calendar#selectDay",
76
+ name: "day",
77
+ class:
78
+ tokens(
79
+ BASE_CLASS,
80
+ "bg-background text-muted-foreground hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground"
81
+ ),
82
+ role: "gridcell",
83
+ tabindex: "-1",
84
+ type: "button"
85
+ ) { "{{dayDate}}" }
86
+ end
87
+ end
88
+
89
+ def date_template(target, &block)
90
+ template_tag(data: {rbui__calendar_target: target}) do
91
+ td(
92
+ class:
93
+ "relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected])]:rounded-md",
94
+ role: "presentation",
95
+ &block
96
+ )
97
+ end
98
+ end
99
+
100
+ def default_attrs
101
+ {}
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class CalendarHeader < Base
5
+ def view_template(&)
6
+ div(**attrs, &)
7
+ end
8
+
9
+ private
10
+
11
+ def default_attrs
12
+ {
13
+ class: "flex justify-center pt-1 relative items-center"
14
+ }
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBUI
4
+ class CalendarNext < Base
5
+ def view_template(&block)
6
+ button(**attrs) do
7
+ icon
8
+ end
9
+ end
10
+
11
+ private
12
+
13
+ def icon
14
+ svg(
15
+ width: "15",
16
+ height: "15",
17
+ viewbox: "0 0 15 15",
18
+ fill: "none",
19
+ xmlns: "http://www.w3.org/2000/svg",
20
+ class: "h-4 w-4"
21
+ ) do |s|
22
+ s.path(
23
+ d:
24
+ "M6.1584 3.13508C6.35985 2.94621 6.67627 2.95642 6.86514 3.15788L10.6151 7.15788C10.7954 7.3502 10.7954 7.64949 10.6151 7.84182L6.86514 11.8418C6.67627 12.0433 6.35985 12.0535 6.1584 11.8646C5.95694 11.6757 5.94673 11.3593 6.1356 11.1579L9.565 7.49985L6.1356 3.84182C5.94673 3.64036 5.95694 3.32394 6.1584 3.13508Z",
25
+ fill: "currentColor",
26
+ fill_rule: "evenodd",
27
+ clip_rule: "evenodd"
28
+ )
29
+ end
30
+ end
31
+
32
+ def default_attrs
33
+ {
34
+ name: "next-month",
35
+ aria_label: "Go to next month",
36
+ class:
37
+ "inline-flex items-center justify-center rounded-md text-sm font-medium 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 hover:bg-accent hover:text-accent-foreground h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100 absolute right-1",
38
+ type: "button",
39
+ data_action: "click->rbui--calendar#nextMonth"
40
+ }
41
+ end
42
+ end
43
+ end