ruby_ui 1.0.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +4 -0
  4. data/lib/generators/ruby_ui/component_generator.rb +5 -1
  5. data/lib/generators/ruby_ui/dependencies.yml +10 -0
  6. data/lib/generators/ruby_ui/install/docs_generator.rb +33 -0
  7. data/lib/generators/ruby_ui/install/install_generator.rb +1 -1
  8. data/lib/generators/ruby_ui/javascript_utils.rb +4 -0
  9. data/lib/ruby_ui/accordion/accordion_docs.rb +53 -0
  10. data/lib/ruby_ui/alert/alert_docs.rb +135 -0
  11. data/lib/ruby_ui/alert_dialog/alert_dialog_docs.rb +35 -0
  12. data/lib/ruby_ui/aspect_ratio/aspect_ratio_docs.rb +64 -0
  13. data/lib/ruby_ui/avatar/avatar_docs.rb +92 -0
  14. data/lib/ruby_ui/badge/badge_docs.rb +80 -0
  15. data/lib/ruby_ui/breadcrumb/breadcrumb_docs.rb +116 -0
  16. data/lib/ruby_ui/button/button_docs.rb +143 -0
  17. data/lib/ruby_ui/calendar/calendar_docs.rb +34 -0
  18. data/lib/ruby_ui/card/card_docs.rb +114 -0
  19. data/lib/ruby_ui/carousel/carousel_docs.rb +104 -0
  20. data/lib/ruby_ui/chart/chart_docs.rb +115 -0
  21. data/lib/ruby_ui/checkbox/checkbox.rb +2 -2
  22. data/lib/ruby_ui/checkbox/checkbox_docs.rb +41 -0
  23. data/lib/ruby_ui/clipboard/clipboard_docs.rb +30 -0
  24. data/lib/ruby_ui/codeblock/codeblock_docs.rb +55 -0
  25. data/lib/ruby_ui/collapsible/collapsible_docs.rb +96 -0
  26. data/lib/ruby_ui/combobox/combobox.rb +7 -1
  27. data/lib/ruby_ui/combobox/combobox_badge.rb +17 -0
  28. data/lib/ruby_ui/combobox/combobox_badge_trigger.rb +47 -0
  29. data/lib/ruby_ui/combobox/combobox_checkbox.rb +1 -7
  30. data/lib/ruby_ui/combobox/combobox_clear_button.rb +40 -0
  31. data/lib/ruby_ui/combobox/combobox_controller.js +252 -47
  32. data/lib/ruby_ui/combobox/combobox_docs.rb +286 -0
  33. data/lib/ruby_ui/combobox/combobox_input_trigger.rb +64 -0
  34. data/lib/ruby_ui/combobox/combobox_item.rb +5 -7
  35. data/lib/ruby_ui/combobox/combobox_item_indicator.rb +30 -0
  36. data/lib/ruby_ui/combobox/combobox_list_group.rb +1 -1
  37. data/lib/ruby_ui/combobox/combobox_popover.rb +1 -5
  38. data/lib/ruby_ui/combobox/combobox_radio.rb +1 -8
  39. data/lib/ruby_ui/combobox/combobox_toggle_all_checkbox.rb +1 -6
  40. data/lib/ruby_ui/combobox/combobox_trigger.rb +19 -19
  41. data/lib/ruby_ui/command/command_docs.rb +154 -0
  42. data/lib/ruby_ui/context_menu/context_menu.rb +1 -1
  43. data/lib/ruby_ui/context_menu/context_menu_docs.rb +85 -0
  44. data/lib/ruby_ui/data_table/data_table.rb +29 -0
  45. data/lib/ruby_ui/data_table/data_table_bulk_actions.rb +18 -0
  46. data/lib/ruby_ui/data_table/data_table_column_toggle.rb +62 -0
  47. data/lib/ruby_ui/data_table/data_table_column_visibility_controller.js +14 -0
  48. data/lib/ruby_ui/data_table/data_table_controller.js +57 -0
  49. data/lib/ruby_ui/data_table/data_table_docs.rb +180 -0
  50. data/lib/ruby_ui/data_table/data_table_expand_toggle.rb +53 -0
  51. data/lib/ruby_ui/data_table/data_table_form.rb +39 -0
  52. data/lib/ruby_ui/data_table/data_table_kaminari_adapter.rb +17 -0
  53. data/lib/ruby_ui/data_table/data_table_manual_adapter.rb +17 -0
  54. data/lib/ruby_ui/data_table/data_table_pagination.rb +100 -0
  55. data/lib/ruby_ui/data_table/data_table_pagination_bar.rb +15 -0
  56. data/lib/ruby_ui/data_table/data_table_pagy_adapter.rb +17 -0
  57. data/lib/ruby_ui/data_table/data_table_per_page_select.rb +35 -0
  58. data/lib/ruby_ui/data_table/data_table_row_checkbox.rb +30 -0
  59. data/lib/ruby_ui/data_table/data_table_search.rb +57 -0
  60. data/lib/ruby_ui/data_table/data_table_search_controller.js +62 -0
  61. data/lib/ruby_ui/data_table/data_table_select_all_checkbox.rb +21 -0
  62. data/lib/ruby_ui/data_table/data_table_selection_summary.rb +25 -0
  63. data/lib/ruby_ui/data_table/data_table_sort_head.rb +112 -0
  64. data/lib/ruby_ui/data_table/data_table_toolbar.rb +15 -0
  65. data/lib/ruby_ui/dialog/dialog_docs.rb +102 -0
  66. data/lib/ruby_ui/docs/base.rb +90 -0
  67. data/lib/ruby_ui/docs/component_setup_tabs.rb +15 -0
  68. data/lib/ruby_ui/docs/components_table.rb +13 -0
  69. data/lib/ruby_ui/docs/header.rb +17 -0
  70. data/lib/ruby_ui/docs/sidebar_examples.rb +22 -0
  71. data/lib/ruby_ui/docs/visual_code_example.rb +22 -0
  72. data/lib/ruby_ui/dropdown_menu/dropdown_menu_docs.rb +212 -0
  73. data/lib/ruby_ui/form/form_docs.rb +178 -0
  74. data/lib/ruby_ui/form/form_field.rb +1 -1
  75. data/lib/ruby_ui/form/form_field_error.rb +1 -1
  76. data/lib/ruby_ui/form/form_field_hint.rb +1 -1
  77. data/lib/ruby_ui/form/form_field_label.rb +1 -1
  78. data/lib/ruby_ui/hover_card/hover_card_docs.rb +71 -0
  79. data/lib/ruby_ui/input/input.rb +4 -3
  80. data/lib/ruby_ui/input/input_docs.rb +68 -0
  81. data/lib/ruby_ui/link/link_docs.rb +106 -0
  82. data/lib/ruby_ui/masked_input/masked_input.rb +11 -1
  83. data/lib/ruby_ui/masked_input/masked_input_controller.js +13 -0
  84. data/lib/ruby_ui/masked_input/masked_input_docs.rb +47 -0
  85. data/lib/ruby_ui/native_select/native_select.rb +39 -0
  86. data/lib/ruby_ui/native_select/native_select_docs.rb +83 -0
  87. data/lib/ruby_ui/native_select/native_select_group.rb +15 -0
  88. data/lib/ruby_ui/native_select/native_select_icon.rb +39 -0
  89. data/lib/ruby_ui/native_select/native_select_option.rb +15 -0
  90. data/lib/ruby_ui/pagination/pagination_docs.rb +127 -0
  91. data/lib/ruby_ui/popover/popover_docs.rb +971 -0
  92. data/lib/ruby_ui/progress/progress_docs.rb +27 -0
  93. data/lib/ruby_ui/radio_button/radio_button.rb +1 -1
  94. data/lib/ruby_ui/radio_button/radio_button_docs.rb +53 -0
  95. data/lib/ruby_ui/select/select_docs.rb +129 -0
  96. data/lib/ruby_ui/separator/separator_docs.rb +36 -0
  97. data/lib/ruby_ui/sheet/sheet_content.rb +1 -1
  98. data/lib/ruby_ui/sheet/sheet_docs.rb +76 -0
  99. data/lib/ruby_ui/shortcut_key/shortcut_key_docs.rb +29 -0
  100. data/lib/ruby_ui/sidebar/sidebar_docs.rb +176 -0
  101. data/lib/ruby_ui/skeleton/skeleton_docs.rb +29 -0
  102. data/lib/ruby_ui/switch/switch_docs.rb +46 -0
  103. data/lib/ruby_ui/table/table_docs.rb +102 -0
  104. data/lib/ruby_ui/tabs/tabs_docs.rb +211 -0
  105. data/lib/ruby_ui/textarea/textarea_docs.rb +54 -0
  106. data/lib/ruby_ui/theme_toggle/theme_toggle_docs.rb +71 -0
  107. data/lib/ruby_ui/tooltip/tooltip_docs.rb +52 -0
  108. data/lib/ruby_ui/typography/typography_docs.rb +107 -0
  109. data/lib/ruby_ui.rb +1 -1
  110. metadata +90 -3
@@ -0,0 +1,178 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Views::Docs::Form < Views::Base
4
+ def view_template
5
+ component = "Form"
6
+ div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
7
+ render Docs::Header.new(title: "Form", description: "Building forms with built-in client-side validations.")
8
+
9
+ Heading(level: 2) { "Usage" }
10
+
11
+ render Docs::VisualCodeExample.new(title: "Example", context: self) do
12
+ <<~RUBY
13
+ Form(class: "w-2/3 space-y-6") do
14
+ FormField do
15
+ FormFieldLabel { "Default error" }
16
+ Input(placeholder: "Joel Drapper", required: true, minlength: "3") { "Joel Drapper" }
17
+ FormFieldHint()
18
+ FormFieldError()
19
+ end
20
+ Button(type: "submit") { "Save" }
21
+ end
22
+ RUBY
23
+ end
24
+
25
+ render Docs::VisualCodeExample.new(title: "Disabled", context: self) do
26
+ <<~RUBY
27
+ FormField do
28
+ FormFieldLabel { "Disabled" }
29
+ Input(disabled: true, placeholder: "Joel Drapper", required: true, minlength: "3") { "Joel Drapper" }
30
+ end
31
+ RUBY
32
+ end
33
+
34
+ render Docs::VisualCodeExample.new(title: "Aria Disabled", context: self) do
35
+ <<~RUBY
36
+ FormField do
37
+ FormFieldLabel { "Aria Disabled" }
38
+ Input(aria: {disabled: "true"}, placeholder: "Joel Drapper", required: true, minlength: "3") { "Joel Drapper" }
39
+ end
40
+ RUBY
41
+ end
42
+
43
+ render Docs::VisualCodeExample.new(title: "Custom error message", context: self) do
44
+ <<~RUBY
45
+ Form(class: "w-2/3 space-y-6") do
46
+ FormField do
47
+ FormFieldLabel { "Custom error message" }
48
+ Input(placeholder: "joel@drapper.me", required: true, data_value_missing: "Custom error message")
49
+ FormFieldError()
50
+ end
51
+ Button(type: "submit") { "Save" }
52
+ end
53
+ RUBY
54
+ end
55
+
56
+ render Docs::VisualCodeExample.new(title: "Backend error", context: self) do
57
+ <<~RUBY
58
+ Form(class: "w-2/3 space-y-6") do
59
+ FormField do
60
+ FormFieldLabel { "Backend error" }
61
+ Input(placeholder: "Joel Drapper", required: true)
62
+ FormFieldError { "Error from backend" }
63
+ end
64
+ Button(type: "submit") { "Save" }
65
+ end
66
+ RUBY
67
+ end
68
+
69
+ render Docs::VisualCodeExample.new(title: "Checkbox", context: self) do
70
+ <<~RUBY
71
+ Form(class: "w-2/3 space-y-6") do
72
+ FormField do
73
+ Checkbox(required: true)
74
+ label(
75
+ class:
76
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
77
+ ) { " Accept terms and conditions " }
78
+ FormFieldError()
79
+ end
80
+ Button(type: "submit") { "Save" }
81
+ end
82
+ RUBY
83
+ end
84
+
85
+ render Docs::VisualCodeExample.new(title: "Select", context: self) do
86
+ <<~RUBY
87
+ Form(class: "w-2/3 space-y-6") do
88
+ FormField do
89
+ FormFieldLabel { "Select" }
90
+ Select do
91
+ SelectInput(required: true)
92
+ SelectTrigger do
93
+ SelectValue(placeholder: "Select a fruit")
94
+ end
95
+ SelectContent() do
96
+ SelectGroup do
97
+ SelectLabel { "Fruits" }
98
+ SelectItem(value: "apple") { "Apple" }
99
+ SelectItem(value: "orange") { "Orange" }
100
+ SelectItem(value: "banana") { "Banana" }
101
+ SelectItem(value: "watermelon") { "Watermelon" }
102
+ end
103
+ end
104
+ end
105
+ FormFieldError()
106
+ end
107
+ Button(type: "submit") { "Save" }
108
+ end
109
+ RUBY
110
+ end
111
+
112
+ render Docs::VisualCodeExample.new(title: "Combobox", context: self) do
113
+ <<~RUBY
114
+ Form(class: "w-2/3 space-y-6") do
115
+ FormField do
116
+ FormFieldLabel { "Combobox" }
117
+
118
+ Combobox do
119
+ ComboboxTrigger placeholder: "Pick value"
120
+
121
+ ComboboxPopover do
122
+ ComboboxSearchInput(placeholder: "Pick value or type anything")
123
+
124
+ ComboboxList do
125
+ ComboboxEmptyState { "No result" }
126
+
127
+ ComboboxListGroup label: "Fruits" do
128
+ ComboboxItem do
129
+ ComboboxRadio(name: "food", value: "apple", required: true)
130
+ span { "Apple" }
131
+ end
132
+
133
+ ComboboxItem do
134
+ ComboboxRadio(name: "food", value: "banana", required: true)
135
+ span { "Banana" }
136
+ end
137
+ end
138
+
139
+ ComboboxListGroup label: "Vegetable" do
140
+ ComboboxItem do
141
+ ComboboxRadio(name: "food", value: "brocoli", required: true)
142
+ span { "Broccoli" }
143
+ end
144
+
145
+ ComboboxItem do
146
+ ComboboxRadio(name: "food", value: "carrot", required: true)
147
+ span { "Carrot" }
148
+ end
149
+ end
150
+
151
+ ComboboxListGroup label: "Others" do
152
+ ComboboxItem do
153
+ ComboboxRadio(name: "food", value: "chocolate", required: true)
154
+ span { "Chocolate" }
155
+ end
156
+
157
+ ComboboxItem do
158
+ ComboboxRadio(name: "food", value: "milk", required: true)
159
+ span { "Milk" }
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
165
+
166
+ FormFieldError()
167
+ end
168
+ Button(type: "submit") { "Save" }
169
+ end
170
+ RUBY
171
+ end
172
+
173
+ render Components::ComponentSetup::Tabs.new(component_name: component)
174
+
175
+ render Docs::ComponentsTable.new(component_files(component))
176
+ end
177
+ end
178
+ end
@@ -13,7 +13,7 @@ module RubyUI
13
13
  data: {
14
14
  controller: "ruby-ui--form-field"
15
15
  },
16
- class: "space-y-2"
16
+ class: "flex flex-col gap-2"
17
17
  }
18
18
  end
19
19
  end
@@ -13,7 +13,7 @@ module RubyUI
13
13
  data: {
14
14
  ruby_ui__form_field_target: "error"
15
15
  },
16
- class: "text-sm font-medium text-destructive"
16
+ class: "empty:hidden text-sm font-medium text-destructive"
17
17
  }
18
18
  end
19
19
  end
@@ -9,7 +9,7 @@ module RubyUI
9
9
  private
10
10
 
11
11
  def default_attrs
12
- {class: "text-sm text-muted-foreground"}
12
+ {class: "empty:hidden text-sm text-muted-foreground"}
13
13
  end
14
14
  end
15
15
  end
@@ -11,7 +11,7 @@ module RubyUI
11
11
  def default_attrs
12
12
  {
13
13
  class: [
14
- "text-sm font-medium leading-none",
14
+ "empty:hidden text-sm font-medium leading-none",
15
15
  "peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
16
16
  "peer-aria-disabled:cursor-not-allowed peer-aria-disabled:opacity-70 peer-aria-disabled:pointer-events-none"
17
17
  ]
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Views::Docs::HoverCard < Views::Base
4
+ def view_template
5
+ component = "HoverCard"
6
+
7
+ div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
8
+ render Docs::Header.new(title: "Hover Card", description: "For sighted users to preview content available behind a link.")
9
+
10
+ Heading(level: 2) { "Usage" }
11
+
12
+ render Docs::VisualCodeExample.new(title: "Example", context: self) do
13
+ <<~RUBY
14
+ HoverCard do
15
+ HoverCardTrigger do
16
+ Button(variant: :link) { "@joeldrapper" } # Make this a link in order to navigate somewhere
17
+ end
18
+ HoverCardContent do
19
+ div(class: "flex justify-between space-x-4") do
20
+ Avatar do
21
+ AvatarImage(src: "https://avatars.githubusercontent.com/u/246692?v=4", alt: "joeldrapper")
22
+ AvatarFallback { "JD" }
23
+ end
24
+ div(class: "space-y-1") do
25
+ h4(class: "text-sm font-medium") { "@joeldrapper" }
26
+ p(class: "text-sm") do
27
+ "Creator of Phlex Components. Ruby on Rails developer."
28
+ end
29
+ div(class: "flex items-center pt-2") do
30
+ svg(
31
+ width: "15",
32
+ height: "15",
33
+ viewbox: "0 0 15 15",
34
+ fill: "none",
35
+ xmlns: "http://www.w3.org/2000/svg",
36
+ class: "mr-2 h-4 w-4 opacity-70"
37
+ ) do |s|
38
+ s.path(
39
+ d:
40
+ "M4.5 1C4.77614 1 5 1.22386 5 1.5V2H10V1.5C10 1.22386 10.2239 1 10.5 1C10.7761 1 11 1.22386 11 1.5V2H12.5C13.3284 2 14 2.67157 14 3.5V12.5C14 13.3284 13.3284 14 12.5 14H2.5C1.67157 14 1 13.3284 1 12.5V3.5C1 2.67157 1.67157 2 2.5 2H4V1.5C4 1.22386 4.22386 1 4.5 1ZM10 3V3.5C10 3.77614 10.2239 4 10.5 4C10.7761 4 11 3.77614 11 3.5V3H12.5C12.7761 3 13 3.22386 13 3.5V5H2V3.5C2 3.22386 2.22386 3 2.5 3H4V3.5C4 3.77614 4.22386 4 4.5 4C4.77614 4 5 3.77614 5 3.5V3H10ZM2 6V12.5C2 12.7761 2.22386 13 2.5 13H12.5C12.7761 13 13 12.7761 13 12.5V6H2ZM7 7.5C7 7.22386 7.22386 7 7.5 7C7.77614 7 8 7.22386 8 7.5C8 7.77614 7.77614 8 7.5 8C7.22386 8 7 7.77614 7 7.5ZM9.5 7C9.22386 7 9 7.22386 9 7.5C9 7.77614 9.22386 8 9.5 8C9.77614 8 10 7.77614 10 7.5C10 7.22386 9.77614 7 9.5 7ZM11 7.5C11 7.22386 11.2239 7 11.5 7C11.7761 7 12 7.22386 12 7.5C12 7.77614 11.7761 8 11.5 8C11.2239 8 11 7.77614 11 7.5ZM11.5 9C11.2239 9 11 9.22386 11 9.5C11 9.77614 11.2239 10 11.5 10C11.7761 10 12 9.77614 12 9.5C12 9.22386 11.7761 9 11.5 9ZM9 9.5C9 9.22386 9.22386 9 9.5 9C9.77614 9 10 9.22386 10 9.5C10 9.77614 9.77614 10 9.5 10C9.22386 10 9 9.77614 9 9.5ZM7.5 9C7.22386 9 7 9.22386 7 9.5C7 9.77614 7.22386 10 7.5 10C7.77614 10 8 9.77614 8 9.5C8 9.22386 7.77614 9 7.5 9ZM5 9.5C5 9.22386 5.22386 9 5.5 9C5.77614 9 6 9.22386 6 9.5C6 9.77614 5.77614 10 5.5 10C5.22386 10 5 9.77614 5 9.5ZM3.5 9C3.22386 9 3 9.22386 3 9.5C3 9.77614 3.22386 10 3.5 10C3.77614 10 4 9.77614 4 9.5C4 9.22386 3.77614 9 3.5 9ZM3 11.5C3 11.2239 3.22386 11 3.5 11C3.77614 11 4 11.2239 4 11.5C4 11.7761 3.77614 12 3.5 12C3.22386 12 3 11.7761 3 11.5ZM5.5 11C5.22386 11 5 11.2239 5 11.5C5 11.7761 5.22386 12 5.5 12C5.77614 12 6 11.7761 6 11.5C6 11.2239 5.77614 11 5.5 11ZM7 11.5C7 11.2239 7.22386 11 7.5 11C7.77614 11 8 11.2239 8 11.5C8 11.7761 7.77614 12 7.5 12C7.22386 12 7 11.7761 7 11.5ZM9.5 11C9.22386 11 9 11.2239 9 11.5C9 11.7761 9.22386 12 9.5 12C9.77614 12 10 11.7761 10 11.5C10 11.2239 9.77614 11 9.5 11Z",
41
+ fill: "currentColor",
42
+ fill_rule: "evenodd",
43
+ clip_rule: "evenodd"
44
+ )
45
+ end
46
+ span(class: "text-xs text-muted-foreground") { "Joined December 2021" }
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ RUBY
53
+ end
54
+
55
+ render Components::ComponentSetup::Tabs.new(component_name: component)
56
+
57
+ render Docs::ComponentsTable.new(component_files(component))
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ # def components
64
+ # [
65
+ # Docs::ComponentStruct.new(name: "PopoverController", source: "https://github.com/PhlexUI/phlex_ui_stimulus/blob/main/controllers/popover_controller.js", built_using: :stimulus),
66
+ # Docs::ComponentStruct.new(name: "HoverCard", source: "https://github.com/PhlexUI/phlex_ui/blob/main/lib/phlex_ui/hover_card.rb", built_using: :phlex),
67
+ # Docs::ComponentStruct.new(name: "HoverCardTrigger", source: "https://github.com/PhlexUI/phlex_ui/blob/main/lib/phlex_ui/hover_card/trigger.rb", built_using: :phlex),
68
+ # Docs::ComponentStruct.new(name: "HoverCardContent", source: "https://github.com/PhlexUI/phlex_ui/blob/main/lib/phlex_ui/hover_card/content.rb", built_using: :phlex)
69
+ # ]
70
+ # end
71
+ end
@@ -20,12 +20,13 @@ module RubyUI
20
20
  action: "input->ruby-ui--form-field#onInput invalid->ruby-ui--form-field#onInvalid"
21
21
  },
22
22
  class: [
23
- "flex h-9 w-full rounded-md border bg-background px-3 py-1 text-sm shadow-sm transition-colors border-border",
23
+ "flex h-9 w-full rounded-md border bg-background px-3 py-1 text-sm shadow-xs transition-[color,box-shadow] border-border ring-0 ring-ring/0",
24
24
  "placeholder:text-muted-foreground",
25
25
  "disabled:cursor-not-allowed disabled:opacity-50",
26
26
  "file:border-0 file:bg-transparent file:text-sm file:font-medium",
27
- "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
28
- "aria-disabled:cursor-not-allowed aria-disabled:opacity-50 aria-disabled:pointer-events-none"
27
+ "aria-disabled:cursor-not-allowed aria-disabled:opacity-50 aria-disabled:pointer-events-none",
28
+ "focus-visible:outline-none focus-visible:ring-ring/50 focus-visible:ring-2 focus-visible:border-ring focus-visible:shadow-sm",
29
+ (@type.to_s == "file") ? "pt-[7px]" : ""
29
30
  ]
30
31
  }
31
32
  end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Views::Docs::Input < Views::Base
4
+ def view_template
5
+ component = "Input"
6
+
7
+ div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
8
+ render Docs::Header.new(title: "Input", description: "Displays a form input field or a component that looks like an input field.")
9
+
10
+ Heading(level: 2) { "Usage" }
11
+
12
+ render Docs::VisualCodeExample.new(title: "Email", context: self) do
13
+ <<~RUBY
14
+ div(class: 'grid w-full max-w-sm items-center gap-1.5') do
15
+ Input(type: "email", placeholder: "Email")
16
+ end
17
+ RUBY
18
+ end
19
+
20
+ render Docs::VisualCodeExample.new(title: "File", context: self) do
21
+ <<~RUBY
22
+ div(class: "grid w-full max-w-sm items-center gap-1.5") do
23
+ label(for: "picture") { "Picture" }
24
+ Input(type: "file", id: "picture")
25
+ end
26
+ RUBY
27
+ end
28
+
29
+ render Docs::VisualCodeExample.new(title: "Disabled", context: self) do
30
+ <<~RUBY
31
+ div(class: 'grid w-full max-w-sm items-center gap-1.5') do
32
+ Input(disabled: true, type: "email", placeholder: "Email")
33
+ end
34
+ RUBY
35
+ end
36
+
37
+ render Docs::VisualCodeExample.new(title: "Aria Disabled", context: self) do
38
+ <<~RUBY
39
+ div(class: 'grid w-full max-w-sm items-center gap-1.5') do
40
+ Input(aria: {disabled: "true"}, type: "email", placeholder: "Email")
41
+ end
42
+ RUBY
43
+ end
44
+
45
+ render Docs::VisualCodeExample.new(title: "With label", context: self) do
46
+ <<~RUBY
47
+ div(class: 'grid w-full max-w-sm items-center gap-1.5') do
48
+ label(for: "email1") { "Email" }
49
+ Input(type: "email", placeholder: "Email", id: "email1")
50
+ end
51
+ RUBY
52
+ end
53
+
54
+ render Docs::VisualCodeExample.new(title: "With button", context: self) do
55
+ <<~RUBY
56
+ div(class: 'flex w-full max-w-sm items-center space-x-2') do
57
+ Input(type: "email", placeholder: "Email")
58
+ Button { "Subscribe" }
59
+ end
60
+ RUBY
61
+ end
62
+
63
+ render Components::ComponentSetup::Tabs.new(component_name: component)
64
+
65
+ render Docs::ComponentsTable.new(component_files(component))
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Views::Docs::Link < Views::Base
4
+ def view_template
5
+ component = "Link"
6
+
7
+ div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
8
+ render Docs::Header.new(title: "Link", description: "Displays a link that looks like a button or underline link.")
9
+
10
+ Heading(level: 2) { "Usage" }
11
+
12
+ render Docs::VisualCodeExample.new(title: "Example", description: "This is the default appearance of a Link", context: self) do
13
+ <<~RUBY
14
+ Link(href: "#") { "Link" }
15
+ RUBY
16
+ end
17
+
18
+ render Docs::VisualCodeExample.new(title: "Aria Disabled", context: self) do
19
+ <<~RUBY
20
+ Link(aria: {disabled: "true"}, href: "#") { "Link" }
21
+ RUBY
22
+ end
23
+
24
+ render Docs::VisualCodeExample.new(title: "Primary", description: "This is the primary variant of a Link", context: self) do
25
+ <<~RUBY
26
+ Link(href: "#", variant: :primary) { "Primary" }
27
+ RUBY
28
+ end
29
+
30
+ render Docs::VisualCodeExample.new(title: "Secondary", description: "This is the secondary variant of a Link", context: self) do
31
+ <<~RUBY
32
+ Link(href: "#", variant: :secondary) { "Secondary" }
33
+ RUBY
34
+ end
35
+
36
+ render Docs::VisualCodeExample.new(title: "Destructive", description: "This is the destructive variant of a Link", context: self) do
37
+ <<~RUBY
38
+ Link(href: "#", variant: :destructive) { "Destructive" }
39
+ RUBY
40
+ end
41
+
42
+ render Docs::VisualCodeExample.new(title: "Icon", description: "This is the icon variant of a Link", context: self) do
43
+ <<~RUBY
44
+ Link(href: "#", variant: :outline, icon: true) do
45
+ chevron_icon
46
+ end
47
+ RUBY
48
+ end
49
+
50
+ render Docs::VisualCodeExample.new(title: "With Icon", description: "This is the primary variant of a Link with an icon", context: self) do
51
+ <<~RUBY
52
+ Link(href: "#", variant: :primary) do
53
+ email_icon
54
+ span { "Login with Email" }
55
+ end
56
+ RUBY
57
+ end
58
+
59
+ render Docs::VisualCodeExample.new(title: "Ghost", description: "This is the ghost variant of a Link", context: self) do
60
+ <<~RUBY
61
+ Link(href: "#", variant: :ghost) { "Ghost" }
62
+ RUBY
63
+ end
64
+
65
+ render Components::ComponentSetup::Tabs.new(component_name: component)
66
+
67
+ render Docs::ComponentsTable.new(component_files(component))
68
+ end
69
+ end
70
+
71
+ private
72
+
73
+ def chevron_icon
74
+ svg(
75
+ xmlns: "http://www.w3.org/2000/svg",
76
+ viewbox: "0 0 20 20",
77
+ fill: "currentColor",
78
+ class: "w-5 h-5"
79
+ ) do |s|
80
+ s.path(
81
+ fill_rule: "evenodd",
82
+ d:
83
+ "M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z",
84
+ clip_rule: "evenodd"
85
+ )
86
+ end
87
+ end
88
+
89
+ def email_icon
90
+ svg(
91
+ xmlns: "http://www.w3.org/2000/svg",
92
+ fill: "none",
93
+ viewbox: "0 0 24 24",
94
+ stroke_width: "1.5",
95
+ stroke: "currentColor",
96
+ class: "w-4 h-4 mr-2"
97
+ ) do |s|
98
+ s.path(
99
+ stroke_linecap: "round",
100
+ stroke_linejoin: "round",
101
+ d:
102
+ "M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75"
103
+ )
104
+ end
105
+ end
106
+ end
@@ -2,8 +2,18 @@
2
2
 
3
3
  module RubyUI
4
4
  class MaskedInput < Base
5
+ def initialize(save_unmasked: false, **attrs)
6
+ @save_unmasked = save_unmasked
7
+ super(**attrs)
8
+ end
9
+
5
10
  def view_template
6
- Input(type: "text", **attrs)
11
+ if @save_unmasked
12
+ Input(type: "text", **attrs.merge(name: "#{attrs[:name]}-masked"))
13
+ input(type: "hidden", name: attrs[:name], value: attrs[:value])
14
+ else
15
+ Input(type: "text", **attrs)
16
+ end
7
17
  end
8
18
 
9
19
  private
@@ -5,5 +5,18 @@ import { MaskInput } from "maska";
5
5
  export default class extends Controller {
6
6
  connect() {
7
7
  new MaskInput(this.element)
8
+ this.#boundSync = this.#sync.bind(this);
9
+ this.element.addEventListener("maska", this.#boundSync);
10
+ }
11
+
12
+ disconnect() {
13
+ this.element.removeEventListener("maska", this.#boundSync);
14
+ }
15
+
16
+ #boundSync = null;
17
+
18
+ #sync(event) {
19
+ const hidden = this.element.nextElementSibling;
20
+ if (hidden?.type === "hidden") hidden.value = event.detail.unmasked;
8
21
  }
9
22
  }
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Views::Docs::MaskedInput < Views::Base
4
+ def view_template
5
+ component = "MaskedInput"
6
+
7
+ div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
8
+ render Docs::Header.new(title: "MaskedInput", description: "Displays a form input field with applied mask.")
9
+
10
+ Heading(level: 2) { "Usage" }
11
+
12
+ Text do
13
+ plain "For advanced usage, check out the "
14
+ InlineLink(href: "https://beholdr.github.io/maska/v3", target: "_blank") { "Maska website" }
15
+ plain "."
16
+ end
17
+
18
+ render Docs::VisualCodeExample.new(title: "Phone number", context: self) do
19
+ <<~RUBY
20
+ div(class: 'grid w-full max-w-sm items-center gap-1.5') do
21
+ MaskedInput(data: {maska: "(##) #####-####"})
22
+ end
23
+ RUBY
24
+ end
25
+
26
+ render Docs::VisualCodeExample.new(title: "Hex color code", context: self) do
27
+ <<~RUBY
28
+ div(class: 'grid w-full max-w-sm items-center gap-1.5') do
29
+ MaskedInput(data: {maska: "!#HHHHHH", maska_tokens: "H:[0-9a-fA-F]"})
30
+ end
31
+ RUBY
32
+ end
33
+
34
+ render Docs::VisualCodeExample.new(title: "CPF / CNPJ", context: self) do
35
+ <<~RUBY
36
+ div(class: 'grid w-full max-w-sm items-center gap-1.5') do
37
+ MaskedInput(data: {maska: "['###.###.###-##', '##.###.###/####-##']"})
38
+ end
39
+ RUBY
40
+ end
41
+
42
+ render Components::ComponentSetup::Tabs.new(component_name: component)
43
+
44
+ render Docs::ComponentsTable.new(component_files(component))
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyUI
4
+ class NativeSelect < Base
5
+ def initialize(size: :default, **attrs)
6
+ @size = size
7
+ super(**attrs)
8
+ end
9
+
10
+ def view_template(&block)
11
+ div(
12
+ class: "group/native-select relative w-fit has-[select:disabled]:opacity-50"
13
+ ) do
14
+ select(**attrs, &block)
15
+ render RubyUI::NativeSelectIcon.new
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def default_attrs
22
+ {
23
+ data: {
24
+ ruby_ui__form_field_target: "input",
25
+ action: "change->ruby-ui--form-field#onChange invalid->ruby-ui--form-field#onInvalid"
26
+ },
27
+ class: [
28
+ "border-border bg-transparent text-sm w-full min-w-0 appearance-none rounded-md border py-1 pr-8 pl-2.5 shadow-xs transition-[color,box-shadow] outline-none select-none ring-0 ring-ring/0",
29
+ "placeholder:text-muted-foreground",
30
+ "selection:bg-primary selection:text-primary-foreground",
31
+ "focus-visible:outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-2",
32
+ "disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
33
+ "aria-invalid:ring-destructive/20 aria-invalid:border-destructive aria-invalid:ring-2",
34
+ (@size == :sm) ? "h-7 rounded-md py-0.5" : "h-9"
35
+ ]
36
+ }
37
+ end
38
+ end
39
+ end