neo_components 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. checksums.yaml +7 -0
  2. data/app/assets/icons/academy.svg +3 -0
  3. data/app/assets/icons/adjustments-horizontal.svg +3 -0
  4. data/app/assets/icons/adjustments-vertical.svg +3 -0
  5. data/app/assets/icons/arrow-down-tray.svg +3 -0
  6. data/app/assets/icons/arrow-left.svg +3 -0
  7. data/app/assets/icons/arrow-long-down.svg +3 -0
  8. data/app/assets/icons/arrow-long-right.svg +3 -0
  9. data/app/assets/icons/arrow-long-up.svg +3 -0
  10. data/app/assets/icons/arrow-right.svg +3 -0
  11. data/app/assets/icons/arrow-up-tray.svg +3 -0
  12. data/app/assets/icons/arrow-uturn-left.svg +3 -0
  13. data/app/assets/icons/arrow-uturn-right.svg +3 -0
  14. data/app/assets/icons/assign-user.svg +13 -0
  15. data/app/assets/icons/at-symbol.svg +3 -0
  16. data/app/assets/icons/bars-4.svg +3 -0
  17. data/app/assets/icons/bell.svg +3 -0
  18. data/app/assets/icons/book.svg +3 -0
  19. data/app/assets/icons/bookmark.svg +3 -0
  20. data/app/assets/icons/building-office-2.svg +3 -0
  21. data/app/assets/icons/calendar.svg +3 -0
  22. data/app/assets/icons/celebration.svg +15 -0
  23. data/app/assets/icons/check-badge-solid.svg +3 -0
  24. data/app/assets/icons/check-circle-solid.svg +3 -0
  25. data/app/assets/icons/check-circle.svg +3 -0
  26. data/app/assets/icons/check-list.svg +12 -0
  27. data/app/assets/icons/check.svg +3 -0
  28. data/app/assets/icons/chevron-double-right.svg +3 -0
  29. data/app/assets/icons/chevron-down.svg +3 -0
  30. data/app/assets/icons/chevron-left.svg +3 -0
  31. data/app/assets/icons/chevron-right.svg +3 -0
  32. data/app/assets/icons/chevron-up.svg +3 -0
  33. data/app/assets/icons/circle-stack.svg +3 -0
  34. data/app/assets/icons/clipboard-document-check-solid.svg +4 -0
  35. data/app/assets/icons/clipboard-document-check.svg +3 -0
  36. data/app/assets/icons/clock.svg +3 -0
  37. data/app/assets/icons/complete.svg +3 -0
  38. data/app/assets/icons/course.svg +3 -0
  39. data/app/assets/icons/device-phone-mobile.svg +3 -0
  40. data/app/assets/icons/document-arrow-up.svg +4 -0
  41. data/app/assets/icons/document-text.svg +4 -0
  42. data/app/assets/icons/ellipsis-vertical.svg +3 -0
  43. data/app/assets/icons/exclaimation-circle-solid.svg +3 -0
  44. data/app/assets/icons/eye.svg +4 -0
  45. data/app/assets/icons/flag.svg +3 -0
  46. data/app/assets/icons/funnel.svg +3 -0
  47. data/app/assets/icons/green-circle.svg +3 -0
  48. data/app/assets/icons/green-tick.svg +3 -0
  49. data/app/assets/icons/grid.svg +6 -0
  50. data/app/assets/icons/home.svg +3 -0
  51. data/app/assets/icons/i-vector.svg +3 -0
  52. data/app/assets/icons/lessons.svg +11 -0
  53. data/app/assets/icons/magnifying-glass.svg +3 -0
  54. data/app/assets/icons/minus.svg +3 -0
  55. data/app/assets/icons/numbered-list.svg +3 -0
  56. data/app/assets/icons/pencil.svg +3 -0
  57. data/app/assets/icons/play.svg +3 -0
  58. data/app/assets/icons/plus.svg +3 -0
  59. data/app/assets/icons/power.svg +3 -0
  60. data/app/assets/icons/question-mark-circle.svg +3 -0
  61. data/app/assets/icons/quiz-score.svg +15 -0
  62. data/app/assets/icons/re-invite.svg +3 -0
  63. data/app/assets/icons/red-circle.svg +3 -0
  64. data/app/assets/icons/share.svg +3 -0
  65. data/app/assets/icons/smiley-five.svg +5 -0
  66. data/app/assets/icons/smiley-four.svg +5 -0
  67. data/app/assets/icons/smiley-one.svg +5 -0
  68. data/app/assets/icons/smiley-three.svg +5 -0
  69. data/app/assets/icons/smiley-two.svg +5 -0
  70. data/app/assets/icons/sparkle.svg +3 -0
  71. data/app/assets/icons/star-transparent.svg +3 -0
  72. data/app/assets/icons/stop.svg +4 -0
  73. data/app/assets/icons/support-placeholder.svg +4 -0
  74. data/app/assets/icons/tag.svg +4 -0
  75. data/app/assets/icons/timer.svg +5 -0
  76. data/app/assets/icons/transcript.svg +31 -0
  77. data/app/assets/icons/trash.svg +3 -0
  78. data/app/assets/icons/upload-info.svg +7 -0
  79. data/app/assets/icons/user-circle.svg +3 -0
  80. data/app/assets/icons/user-group.svg +3 -0
  81. data/app/assets/icons/user.svg +3 -0
  82. data/app/assets/icons/users.svg +3 -0
  83. data/app/assets/icons/winner.svg +35 -0
  84. data/app/assets/icons/x-circle-solid.svg +3 -0
  85. data/app/assets/icons/x-circle.svg +3 -0
  86. data/app/assets/icons/x-mark.svg +3 -0
  87. data/app/assets/stylesheets/breadcrumbs.tailwind.css +45 -0
  88. data/app/assets/stylesheets/buttons.tailwind.css +98 -0
  89. data/app/assets/stylesheets/course_progress.css +75 -0
  90. data/app/assets/stylesheets/custom.css +67 -0
  91. data/app/assets/stylesheets/date_picker.tailwind.css +7 -0
  92. data/app/assets/stylesheets/directives.tailwind.css +3 -0
  93. data/app/assets/stylesheets/dropdown.tailwind.css +11 -0
  94. data/app/assets/stylesheets/file_selector.tailwind.css +47 -0
  95. data/app/assets/stylesheets/icons.css.erb +244 -0
  96. data/app/assets/stylesheets/inputs.tailwind.css +53 -0
  97. data/app/assets/stylesheets/menu_component.tailwind.css +39 -0
  98. data/app/assets/stylesheets/mobile_inputs.tailwind.css +11 -0
  99. data/app/assets/stylesheets/modalbox.tailwind.css +35 -0
  100. data/app/assets/stylesheets/profile_icon.tailwind.css +15 -0
  101. data/app/assets/stylesheets/textarea.tailwind.css +43 -0
  102. data/app/assets/stylesheets/tooltip.css +88 -0
  103. data/app/assets/stylesheets/typography.tailwind.css +70 -0
  104. data/app/helpers/ui_helper.rb +31 -0
  105. data/app/helpers/view_component/accordion_component.rb +12 -0
  106. data/app/helpers/view_component/breadcrumbs_component.rb +30 -0
  107. data/app/helpers/view_component/button_component.rb +180 -0
  108. data/app/helpers/view_component/chip_component.rb +54 -0
  109. data/app/helpers/view_component/component_helper.rb +21 -0
  110. data/app/helpers/view_component/course_card_component.rb +9 -0
  111. data/app/helpers/view_component/course_carousal_component.rb +14 -0
  112. data/app/helpers/view_component/course_select_component.rb +32 -0
  113. data/app/helpers/view_component/doc_section_component.rb +10 -0
  114. data/app/helpers/view_component/icon_component.rb +24 -0
  115. data/app/helpers/view_component/input_component/date_picker_component.rb +127 -0
  116. data/app/helpers/view_component/input_component/dropdown_component.rb +99 -0
  117. data/app/helpers/view_component/input_component/file_selector_component.rb +123 -0
  118. data/app/helpers/view_component/input_component/input_checkbox_component.rb +54 -0
  119. data/app/helpers/view_component/input_component/input_mobile_component.rb +68 -0
  120. data/app/helpers/view_component/input_component/input_radio_component.rb +54 -0
  121. data/app/helpers/view_component/input_component/input_text_component.rb +137 -0
  122. data/app/helpers/view_component/input_component/textarea_component.rb +101 -0
  123. data/app/helpers/view_component/input_component.rb +290 -0
  124. data/app/helpers/view_component/input_textarea_component.rb +28 -0
  125. data/app/helpers/view_component/long_course_card_component.rb +10 -0
  126. data/app/helpers/view_component/member_list_component.rb +17 -0
  127. data/app/helpers/view_component/menu_component.rb +31 -0
  128. data/app/helpers/view_component/menu_component_helper.rb +22 -0
  129. data/app/helpers/view_component/menu_item.rb +12 -0
  130. data/app/helpers/view_component/modal_box_component.rb +29 -0
  131. data/app/helpers/view_component/modal_component.rb +12 -0
  132. data/app/helpers/view_component/notification_bar_component.rb +22 -0
  133. data/app/helpers/view_component/paginator_component.rb +9 -0
  134. data/app/helpers/view_component/profile_icon_component.rb +46 -0
  135. data/app/helpers/view_component/progress_component.rb +12 -0
  136. data/app/helpers/view_component/table_component.rb +22 -0
  137. data/app/helpers/view_component/typography_component.rb +83 -0
  138. data/app/javascript/neo_components/controllers/collapsible_controller.js +37 -0
  139. data/app/javascript/neo_components/controllers/date_picker_controller.js +17 -0
  140. data/app/javascript/neo_components/controllers/file_selector_controller.js +145 -0
  141. data/app/javascript/neo_components/controllers/input_mobile_controller.js +7 -0
  142. data/app/javascript/neo_components/controllers/menu_component_controller.js +26 -0
  143. data/app/javascript/neo_components/controllers/modal_loader_controller.js +13 -0
  144. data/app/javascript/neo_components/controllers/modals_controller.js +26 -0
  145. data/app/javascript/neo_components/controllers/notification_bar_controller.js +9 -0
  146. data/app/javascript/neo_components/controllers/pagination_controller.js +11 -0
  147. data/app/javascript/neo_components/controllers/tab_change_controller.js +23 -0
  148. data/app/javascript/neo_components/controllers/tabs_controller.js +29 -0
  149. data/app/javascript/neo_components/controllers/text_clamp_controller.js +29 -0
  150. data/app/views/shared/components/_progress_bar_short.html.erb +8 -0
  151. data/app/views/shared/components/_tooltip.html.erb +7 -0
  152. data/app/views/view_components/accordion_component/_accordion.html.erb +22 -0
  153. data/app/views/view_components/breadcrumbs_component/_breadcrumbs.html.erb +38 -0
  154. data/app/views/view_components/button_component/_button.html.erb +13 -0
  155. data/app/views/view_components/buttons/_danger.html.erb +30 -0
  156. data/app/views/view_components/buttons/_primary.html.erb +31 -0
  157. data/app/views/view_components/buttons/_secondary.html.erb +29 -0
  158. data/app/views/view_components/chip_component/_chip_component.html.erb +9 -0
  159. data/app/views/view_components/course_carousal/_course_card_component.html.erb +65 -0
  160. data/app/views/view_components/course_carousal/_course_carousal_body_component.html.erb +25 -0
  161. data/app/views/view_components/course_carousal/_course_carousal_component.html.erb +8 -0
  162. data/app/views/view_components/course_carousal/_long_course_card_component.html.erb +70 -0
  163. data/app/views/view_components/course_select/_course_select_component.html.erb +19 -0
  164. data/app/views/view_components/course_select/_list_component.html.erb +14 -0
  165. data/app/views/view_components/course_select/_list_item_component.html.erb +86 -0
  166. data/app/views/view_components/course_select/_load_more.html.erb +17 -0
  167. data/app/views/view_components/course_select/_search_component.html.erb +48 -0
  168. data/app/views/view_components/course_select/_sidebar_component.html.erb +41 -0
  169. data/app/views/view_components/doc_section/_doc_section_component.html.erb +6 -0
  170. data/app/views/view_components/inputs/_checkbox_field.html.erb +19 -0
  171. data/app/views/view_components/inputs/_date_select_component.html.erb +37 -0
  172. data/app/views/view_components/inputs/_dropdown_field.html.erb +22 -0
  173. data/app/views/view_components/inputs/_file_selector.html.erb +16 -0
  174. data/app/views/view_components/inputs/_input_checkbox_component.html.erb +7 -0
  175. data/app/views/view_components/inputs/_input_mobile_component.html.erb +16 -0
  176. data/app/views/view_components/inputs/_input_radio_component.html.erb +7 -0
  177. data/app/views/view_components/inputs/_input_text_component.html.erb +16 -0
  178. data/app/views/view_components/inputs/_mobile_field.html.erb +31 -0
  179. data/app/views/view_components/inputs/_radio_field.html.erb +25 -0
  180. data/app/views/view_components/inputs/_text_field.html.erb +52 -0
  181. data/app/views/view_components/inputs/_textarea.html.erb +26 -0
  182. data/app/views/view_components/inputs/date_picker_component/_date_picker.html.erb +16 -0
  183. data/app/views/view_components/inputs/date_picker_component/_input_box.html.erb +34 -0
  184. data/app/views/view_components/inputs/dropdown_component/_dropdown.html.erb +16 -0
  185. data/app/views/view_components/inputs/dropdown_component/_select_box.html.erb +10 -0
  186. data/app/views/view_components/inputs/file_selector_component/_file_selector_box.html.erb +76 -0
  187. data/app/views/view_components/inputs/input_checkbox/_checkbox.html.erb +20 -0
  188. data/app/views/view_components/inputs/input_mobile/_code.html.erb +13 -0
  189. data/app/views/view_components/inputs/input_mobile/_mobile_box.html.erb +4 -0
  190. data/app/views/view_components/inputs/input_mobile/_number.html.erb +13 -0
  191. data/app/views/view_components/inputs/input_radio/_radio_button.html.erb +14 -0
  192. data/app/views/view_components/inputs/input_text/_text_box.html.erb +33 -0
  193. data/app/views/view_components/inputs/textarea_component/_text_area_box.html.erb +16 -0
  194. data/app/views/view_components/inputs/textarea_component/_textarea.html.erb +16 -0
  195. data/app/views/view_components/member_list/_member_list.html.erb +4 -0
  196. data/app/views/view_components/member_list/_member_search.html.erb +15 -0
  197. data/app/views/view_components/member_list/_members.html.erb +65 -0
  198. data/app/views/view_components/menu_component/_menu_component.html.erb +16 -0
  199. data/app/views/view_components/menu_component/_menu_item_button.html.erb +17 -0
  200. data/app/views/view_components/menu_component/_menu_item_link.html.erb +5 -0
  201. data/app/views/view_components/menu_component_old/_menu_component.html.erb +17 -0
  202. data/app/views/view_components/menu_component_old/_menu_item_button.html.erb +7 -0
  203. data/app/views/view_components/menu_component_old/_menu_item_link.html.erb +5 -0
  204. data/app/views/view_components/modal_component/_modal_box_component.html.erb +28 -0
  205. data/app/views/view_components/modals/_modal_component.html.erb +25 -0
  206. data/app/views/view_components/notification_bar/_notification_bar.html.erb +17 -0
  207. data/app/views/view_components/paginator/_next_page.html.erb +7 -0
  208. data/app/views/view_components/paginator/_paginator_component.html.erb +6 -0
  209. data/app/views/view_components/paginator/_prev_page.html.erb +7 -0
  210. data/app/views/view_components/profile_icon_component/_profile_icon.html.erb +3 -0
  211. data/app/views/view_components/progress_component/_progressbar.html.erb +5 -0
  212. data/app/views/view_components/typography/_h1_component.html.erb +1 -0
  213. data/app/views/view_components/typography/_h2_component.html.erb +1 -0
  214. data/app/views/view_components/typography/_h3_component.html.erb +1 -0
  215. data/app/views/view_components/typography/_heading_component.html.erb +3 -0
  216. data/app/views/view_components/typography/_link_component.html.erb +1 -0
  217. data/app/views/view_components/typography/_linked_text_component.html.erb +3 -0
  218. data/app/views/view_components/typography/_text_component.html.erb +1 -0
  219. data/config/importmap.rb +5 -0
  220. data/lib/neo_components/engine.rb +38 -0
  221. data/lib/neo_components/version.rb +5 -0
  222. data/lib/neo_components.rb +4 -0
  223. metadata +327 -0
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module InputComponent
5
+ class InputCheckboxComponent
6
+ include ViewComponent::ComponentHelper
7
+
8
+ attr_accessor :form, :name, :label, :value, :disabled, :error, :label_position, :html_options
9
+
10
+ def initialize(form:, name:, label:, value:, disabled:, error:, label_position:, html_options:)
11
+ self.form = form
12
+ self.name = name
13
+ self.label = label
14
+ self.label_position = label_position
15
+ self.value = value
16
+ self.html_options = html_options
17
+ self.disabled = disabled
18
+ self.html_options[:disabled] = disabled
19
+ self.html_options[:class] = 'hidden peer'
20
+ self.error = resolve_error(form, name, error)
21
+ end
22
+
23
+ def label_style
24
+ if disabled
25
+ 'text-disabled-color'
26
+ elsif error
27
+ 'text-danger-dark'
28
+ else
29
+ 'text-letter-color group-has-[input:checked]:text-primary group-hover:text-primary-light'
30
+ end
31
+ end
32
+
33
+ def box_style
34
+ if disabled
35
+ 'border-disabled-color'
36
+ elsif error
37
+ 'border-danger-dark'
38
+ else
39
+ 'border-slate-grey-50 group-hover:border-primary-light group-has-[input:checked]:border-primary'
40
+ end
41
+ end
42
+
43
+ def check_style
44
+ if disabled
45
+ 'hidden'
46
+ elsif error
47
+ 'hidden group-has-[input:checked]:flex group-has-[input:checked]:text-danger-dark'
48
+ else
49
+ 'hidden group-has-[input:checked]:flex group-has-[input:checked]:text-primary'
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module InputComponent
5
+ class InputMobileComponent < InputTextComponent
6
+ CODE_WIDTH = {
7
+ md: 'w-16',
8
+ lg: 'w-20'
9
+ }.freeze
10
+
11
+ CODE_SELECT_WIDTH = {
12
+ md: 'w-20',
13
+ lg: 'w-24'
14
+ }.freeze
15
+
16
+ CODE_TEXT = {
17
+ md: 'mobile-code-md',
18
+ lg: 'mobile-code-lg'
19
+ }.freeze
20
+
21
+ attr_accessor :form, :code_name, :name, :label, :type, :code_value, :value, :subtext, :error,
22
+ :icon_name, :icon_position, :disabled, :size, :html_options
23
+
24
+ def initialize(form:, name:, label:, type:, placeholder:, code_value:, value:, subtext:, error:,
25
+ icon_name:, icon_position:, disabled:, size:, html_options:)
26
+ super(form:, name:, label:, type:, placeholder:, value:, subtext:, error:, icon_name:, icon_position:,
27
+ disabled:, size:, html_options:)
28
+ self.code_value = code_value
29
+ self.code_name = name.present? ? "#{name}_code" : 'code'
30
+ end
31
+
32
+ def code_selectable?
33
+ code_value.blank?
34
+ end
35
+
36
+ def error_style
37
+ base = ['text-danger border-danger-dark',
38
+ 'group-focus-within:ring-danger-dark group-focus-within:border-danger-dark']
39
+ base << 'group-focus-within:ring-1' unless code_selectable?
40
+ base.join(' ')
41
+ end
42
+
43
+ def normal_style
44
+ base = ['border-slate-grey-50 group-focus-within:border-primary']
45
+ base << 'group-focus-within:ring-primary' if code_selectable?
46
+ base.join(' ')
47
+ end
48
+
49
+ def code_wrapper_style
50
+ base = ['mobile-code-base']
51
+ color_style = if disabled
52
+ 'border-disabled-color'
53
+ elsif error.present?
54
+ error_style
55
+ elsif code_selectable?
56
+ 'border-slate-grey-50 group-focus:ring-primary group-focus:border-primary'
57
+ else
58
+ 'border-slate-grey-50 group-focus-within:border-primary'
59
+ end
60
+
61
+ size_style = INPUT_WRAPPER_STYLES[size.to_sym]
62
+ code_width = code_selectable? ? CODE_SELECT_WIDTH[size.to_sym] : CODE_WIDTH[size.to_sym]
63
+ code_text = CODE_TEXT[size.to_sym]
64
+ [class_list(base, size_style, color_style), code_width, code_text].join(' ')
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module InputComponent
5
+ class InputRadioComponent
6
+ include ViewComponent::ComponentHelper
7
+
8
+ attr_accessor :form, :name, :label, :value, :disabled, :error, :label_position, :html_options
9
+
10
+ def initialize(form:, name:, label:, value:, disabled:, error:, label_position:, html_options:)
11
+ self.form = form
12
+ self.name = name
13
+ self.label = label
14
+ self.label_position = label_position
15
+ self.value = value
16
+ self.html_options = html_options
17
+ self.disabled = disabled
18
+ self.html_options[:disabled] = disabled
19
+ self.html_options[:class] = 'hidden'
20
+ self.error = resolve_error(form, name, error)
21
+ end
22
+
23
+ def label_style
24
+ if disabled
25
+ 'text-disabled-color'
26
+ elsif error
27
+ 'text-danger-dark'
28
+ else
29
+ 'text-letter-color group-has-[input:checked]:text-primary group-hover:text-primary-light'
30
+ end
31
+ end
32
+
33
+ def radio_circle_style
34
+ if disabled
35
+ 'border-disabled-color'
36
+ elsif error
37
+ 'border-danger-dark'
38
+ else
39
+ 'border-slate-grey-50 group-hover:border-primary-light group-has-[input:checked]:border-primary'
40
+ end
41
+ end
42
+
43
+ def radio_dot_style
44
+ if disabled
45
+ 'bg-white'
46
+ elsif error
47
+ 'group-has-[input:checked]:bg-danger-dark'
48
+ else
49
+ 'group-has-[input:checked]:bg-primary'
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module InputComponent
5
+ class InputTextComponent
6
+ include ViewComponent::ComponentHelper
7
+
8
+ INPUT_SIZE_STYLE = {
9
+ md: 'input-text-md',
10
+ lg: 'input-text-lg'
11
+ }.freeze
12
+
13
+ ICON_SIZE = {
14
+ md: 'input-text-icon-md',
15
+ lg: 'input-text-icon-lg'
16
+ }.freeze
17
+
18
+ INPUT_WRAPPER_STYLES = {
19
+ md: 'input-text-div-base-md',
20
+ lg: 'input-text-div-base-lg'
21
+ }.freeze
22
+
23
+ LABEL_STYLES = {
24
+ md: 'input-text-label-md',
25
+ lg: 'input-text-label-lg'
26
+ }.freeze
27
+
28
+ SUBTEXT_SIZE = {
29
+ md: 'input-text-subtext-md',
30
+ lg: 'input-text-subtext-lg'
31
+ }.freeze
32
+
33
+ attr_accessor :form, :name, :label, :type, :value, :subtext, :error, :icon_name, :icon_position, :disabled, :size,
34
+ :html_options
35
+
36
+ def initialize(form:, name:, label:, type:, placeholder:, value:, subtext:, error:,
37
+ icon_name:, icon_position:, disabled:, size:, html_options:)
38
+ error_message = resolve_error(form, name, error)
39
+
40
+ self.form = form
41
+ self.name = name
42
+ self.label = label
43
+ self.type = type
44
+ self.value = value
45
+ self.subtext = error_message.presence || subtext # Prioritise error over subtext
46
+ self.error = error_message
47
+ self.icon_name = icon_name
48
+ self.icon_position = icon_position
49
+ self.disabled = disabled
50
+ self.size = size
51
+ self.html_options = html_options
52
+ self.html_options[:placeholder] = placeholder
53
+ self.html_options[:class] = input_style
54
+ self.html_options[:disabled] = disabled if disabled
55
+ end
56
+
57
+ def input_style
58
+ base = ['input-text-base']
59
+ color_style = if disabled
60
+ 'text-disabled-color'
61
+ elsif error.present?
62
+ 'text-danger focus:text-danger-dark'
63
+ else
64
+ 'text-disabled-color focus:text-letter-color'
65
+ end
66
+
67
+ size_style = INPUT_SIZE_STYLE[size.to_sym]
68
+ class_list(base, size_style, color_style)
69
+ end
70
+
71
+ def placeholder
72
+ html_options[:placeholder]
73
+ end
74
+
75
+ def placeholder=(value)
76
+ html_options[:placeholder] = value
77
+ end
78
+
79
+ def input_wrapper_style
80
+ base = ['input-text-div-base group']
81
+ color_style = if disabled
82
+ 'border-disabled-color'
83
+ elsif error.present?
84
+ 'border-danger focus-within:border-danger-dark ring-danger-dark'
85
+ else
86
+ 'border-slate-grey-50 focus-within:border-primary ring-primary'
87
+ end
88
+
89
+ size_style = INPUT_WRAPPER_STYLES[size.to_sym]
90
+ class_list(base, size_style, color_style)
91
+ end
92
+
93
+ def label_style
94
+ base = []
95
+ color_style = if disabled
96
+ 'text-disabled-color'
97
+ elsif error.present?
98
+ 'text-danger-dark'
99
+ else
100
+ 'text-letter-color-light group-focus-within:text-primary'
101
+ end
102
+
103
+ size_style = LABEL_STYLES[size.to_sym]
104
+ class_list(base, size_style, color_style)
105
+ end
106
+
107
+ def icon_style
108
+ base = ['input-text-icon-base']
109
+ color_style = if disabled
110
+ 'text-disabled-color'
111
+ elsif error.present?
112
+ 'text-danger-dark'
113
+ else
114
+ 'text-disabled-color group-focus-within:text-letter-color'
115
+ end
116
+ class_list(base, '', color_style)
117
+ end
118
+
119
+ def icon_size
120
+ ICON_SIZE[size.to_sym]
121
+ end
122
+
123
+ def subtext_style
124
+ base = []
125
+ color_style = if disabled
126
+ 'text-disabled-color'
127
+ elsif error.present?
128
+ 'text-danger-dark'
129
+ else
130
+ 'text-letter-color-light'
131
+ end
132
+ size_style = SUBTEXT_SIZE[size.to_sym]
133
+ class_list(base, size_style, color_style)
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module InputComponent
5
+ class TextareaComponent
6
+ include ViewComponent::ComponentHelper
7
+
8
+ TEXTAREA_SIZES = %w[md lg].freeze
9
+
10
+ TEXTAREA_SIZE_STYLE = {
11
+ md: 'textarea-component-md main-text-md-normal',
12
+ lg: 'textarea-component-lg main-text-lg-medium'
13
+ }.freeze
14
+
15
+ LABEL_STYLES = {
16
+ md: 'general-text-sm-normal',
17
+ lg: 'general-text-md-normal'
18
+ }.freeze
19
+
20
+ SUPPORT_TEXT_STYLES = {
21
+ md: 'general-text-sm-normal px-3',
22
+ lg: 'general-text-md-normal px-3 md:px-4'
23
+ }.freeze
24
+
25
+ attr_accessor :form, :name, :label, :placeholder, :value,
26
+ :rows, :size, :support_text, :error, :disabled, :html_options
27
+
28
+ def initialize(form:, name:, label:, placeholder:, value:, rows:, size:, support_text:,
29
+ error:, disabled:, html_options:)
30
+ raise "Incorrect textarea size: #{size}" unless TEXTAREA_SIZES.include?(size)
31
+
32
+ error_message = resolve_error(form, name, error)
33
+
34
+ self.form = form
35
+ self.name = name
36
+ self.label = label
37
+ self.placeholder = placeholder
38
+ self.value = value
39
+ self.rows = rows
40
+ self.size = size
41
+ self.support_text = (error_message.presence || support_text)
42
+ self.error = error_message
43
+ self.disabled = disabled
44
+ self.html_options = html_options
45
+
46
+ self.html_options[:placeholder] = placeholder
47
+ self.html_options[:rows] ||= rows
48
+ self.html_options[:disabled] = true if disabled
49
+ self.html_options[:class] = textarea_style
50
+ end
51
+
52
+ def textarea_style
53
+ base = ['textarea-component-base field-sizing-content']
54
+ size_style = TEXTAREA_SIZE_STYLE[size.to_sym]
55
+
56
+ color_style =
57
+ if disabled
58
+ 'textarea-disabled-state'
59
+ elsif error.present?
60
+ 'textarea-error-state'
61
+ else
62
+ 'textarea-active-state'
63
+ end
64
+
65
+ class_list(base, size_style, color_style)
66
+ end
67
+
68
+ def label_style
69
+ base = ['textarea-label']
70
+ size_style = LABEL_STYLES[size.to_sym]
71
+
72
+ color_style =
73
+ if disabled
74
+ 'text-disabled-color'
75
+ elsif error.present?
76
+ 'text-danger-dark'
77
+ else
78
+ 'text-letter-color-light group-focus-within:text-primary'
79
+ end
80
+
81
+ class_list(base, size_style, color_style)
82
+ end
83
+
84
+ def support_text_style
85
+ base = ['textarea-support-text']
86
+ size_style = SUPPORT_TEXT_STYLES[size.to_sym]
87
+
88
+ color_style =
89
+ if disabled
90
+ 'text-disabled-color'
91
+ elsif error.present?
92
+ 'text-danger-dark'
93
+ else
94
+ 'text-slate-grey-50'
95
+ end
96
+
97
+ class_list(base, size_style, color_style)
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,290 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module InputComponent
5
+ def input_field(form: nil, field_name: nil, label: nil,
6
+ placeholder: nil, width: 'w-56', height: nil, left_icon: nil, right_icon: nil, type: 'text',
7
+ options: [], value: nil, rows: '5', option: nil, html_options: {})
8
+ partial_path = 'view_components/inputs/text_field' unless lookup_context.exists?(partial_path, [], true)
9
+
10
+ html_options[:data] ||= {}
11
+
12
+ render partial: partial_path, locals: {
13
+ form:,
14
+ field_name:,
15
+ label:,
16
+ placeholder:,
17
+ width:,
18
+ height:,
19
+ left_icon:,
20
+ right_icon:,
21
+ type:,
22
+ options:,
23
+ value:,
24
+ rows:,
25
+ option:,
26
+ html_options:
27
+ }
28
+ end
29
+
30
+ def input_radio(form: nil, field_name: nil, label: nil,
31
+ placeholder: 'Enter text', width: 'w-56', height: nil,
32
+ value: nil, option: nil, html_options: {})
33
+ render partial: 'view_components/inputs/radio_field', locals: {
34
+ form:,
35
+ field_name:,
36
+ label:,
37
+ placeholder:,
38
+ width:,
39
+ height:,
40
+ value:,
41
+ option:,
42
+ html_options:
43
+ }
44
+ end
45
+
46
+ def input_dropdown(form: nil, field_name: nil, label: nil,
47
+ width: 'w-56', height: nil, placeholder: nil,
48
+ options: [], value: nil, html_options: {})
49
+ render partial: 'view_components/inputs/dropdown_field', locals: {
50
+ form:,
51
+ field_name:,
52
+ label:,
53
+ width:,
54
+ height:,
55
+ placeholder:,
56
+ options:,
57
+ value:,
58
+ html_options:
59
+ }
60
+ end
61
+
62
+ def input_checkbox(form: nil, field_name: nil, label: nil, width: 'w-56',
63
+ value: nil, allow_multiple: false)
64
+ render partial: 'view_components/inputs/checkbox_field', locals: {
65
+ form:,
66
+ field_name:,
67
+ label:,
68
+ width:,
69
+ value:,
70
+ allow_multiple:
71
+ }
72
+ end
73
+
74
+ def input_mobile(form:, field_name:, placeholder: 'Enter 10-digit mobile number',
75
+ value: nil, label: nil, flag: nil, html_options: {})
76
+ value ||= form.object.public_send(field_name) if form.object.respond_to?(field_name)
77
+
78
+ render partial: 'view_components/inputs/mobile_field', locals: {
79
+ form:,
80
+ field_name:,
81
+ placeholder:,
82
+ value:,
83
+ label:,
84
+ flag:,
85
+ html_options:
86
+ }
87
+ end
88
+
89
+ def input_otp(form:, field_prefix: 'otp', count: 4, input_options: {}, wrapper_options: {})
90
+ content_tag(:div, class: 'flex justify-between gap-6 w-full', **(wrapper_options || {}).except(:data)) do
91
+ safe_join(
92
+ count.times.map do |i|
93
+ field_name = "#{field_prefix}_#{number_to_human(i + 1)}"
94
+
95
+ input_field(
96
+ form:,
97
+ field_name:,
98
+ type: 'text',
99
+ width: 'min-w-16',
100
+ html_options: {
101
+ class: 'input-text-otp',
102
+ maxlength: 1,
103
+ inputmode: 'numeric',
104
+ pattern: '[0-9]*'
105
+ }.merge(input_options)
106
+ )
107
+ end
108
+ )
109
+ end
110
+ end
111
+
112
+ # form component date_select_component
113
+ # @param min minimum date
114
+ # @param maximum date
115
+ def date_select_component(form:, field_name:, min: nil, max: nil, placeholder: 'YYYY-MM-DD')
116
+ render partial: 'view_components/inputs/date_select_component',
117
+ locals: { form:, field_name:, min:, max:, placeholder: }
118
+ end
119
+
120
+ def input_text_component(
121
+ form: nil,
122
+ name: nil,
123
+ label: nil,
124
+ type: 'text',
125
+ placeholder: 'Placeholder',
126
+ value: '',
127
+ subtext: nil,
128
+ error: nil,
129
+ icon_name: nil,
130
+ icon_position: 'right',
131
+ disabled: false,
132
+ size: 'md',
133
+ html_options: {}
134
+ )
135
+ input = InputTextComponent.new(
136
+ form:, name:, label:, type:, placeholder:, value:, subtext:, error:, icon_name:, icon_position:, disabled:,
137
+ size:, html_options:
138
+ )
139
+
140
+ render partial: 'view_components/inputs/input_text_component',
141
+ locals: { input: }
142
+ end
143
+
144
+ def input_radio_component(form: nil, name: nil, label: nil, value: nil, disabled: false, error: nil,
145
+ label_position: 'right',
146
+ html_options: {})
147
+ input = InputRadioComponent.new(
148
+ form:, name:, label:, value:, disabled:, error:, label_position:, html_options:
149
+ )
150
+
151
+ render partial: 'view_components/inputs/input_radio_component',
152
+ locals: { input: }
153
+ end
154
+
155
+ def input_checkbox_component(form: nil, name: nil, label: nil, value: nil, disabled: false, error: nil,
156
+ label_position: 'right',
157
+ html_options: {})
158
+ input = InputCheckboxComponent.new(
159
+ form:, name:, label:, value:, disabled:, error:, label_position:, html_options:
160
+ )
161
+
162
+ render partial: 'view_components/inputs/input_checkbox_component',
163
+ locals: { input: }
164
+ end
165
+
166
+ def file_selector_component(type:, form: nil, name: nil, label: nil, support_text: nil,
167
+ support_text_two: nil, error: nil,
168
+ disabled: false, html_options: {})
169
+ file_selector = FileSelectorComponent.new(
170
+ form:, name:, label:, support_text:, support_text_two:, error:, disabled:, html_options:, type:
171
+ )
172
+
173
+ render partial: 'view_components/inputs/file_selector', locals: { file_selector: }
174
+ end
175
+
176
+ def input_mobile_component(
177
+ form: nil,
178
+ name: nil,
179
+ label: nil,
180
+ placeholder: 'Enter your mobile number',
181
+ country_code: '',
182
+ value: '',
183
+ subtext: nil,
184
+ error: nil,
185
+ icon_name: nil,
186
+ icon_position: 'right',
187
+ disabled: false,
188
+ size: 'md',
189
+ html_options: {}
190
+ )
191
+ input = InputMobileComponent.new(
192
+ form:, name:, label:, type: 'number', placeholder:, code_value: country_code, value:, subtext:, error:,
193
+ icon_name:, icon_position:, disabled:, size:, html_options:
194
+ )
195
+
196
+ render partial: 'view_components/inputs/input_mobile_component',
197
+ locals: { input: }
198
+ end
199
+
200
+ def textarea_component(
201
+ name:,
202
+ placeholder:,
203
+ form: nil,
204
+ label: nil,
205
+ value: nil,
206
+ rows: 1,
207
+ size: 'md',
208
+ support_text: nil,
209
+ error: nil,
210
+ disabled: false,
211
+ html_options: {}
212
+ )
213
+ textarea = TextareaComponent.new(
214
+ form:,
215
+ name:,
216
+ label:,
217
+ placeholder:,
218
+ value:,
219
+ rows:,
220
+ size:,
221
+ support_text:,
222
+ error:,
223
+ disabled:,
224
+ html_options:
225
+ )
226
+
227
+ render partial: 'view_components/inputs/textarea_component/textarea', locals: { textarea: }
228
+ end
229
+
230
+ def dropdown_component(
231
+ form: nil,
232
+ name: nil,
233
+ label: nil,
234
+ options: [],
235
+ value: nil,
236
+ size: 'md',
237
+ support_text: nil,
238
+ error: nil,
239
+ disabled: false,
240
+ html_options: {},
241
+ prompt: nil
242
+ )
243
+ dropdown = DropdownComponent.new(
244
+ form:,
245
+ name:,
246
+ label:,
247
+ options:,
248
+ value:,
249
+ size:,
250
+ support_text:,
251
+ error:,
252
+ disabled:,
253
+ html_options:,
254
+ prompt:
255
+ )
256
+
257
+ render partial: 'view_components/inputs/dropdown_component/dropdown',
258
+ locals: { dropdown: }
259
+ end
260
+
261
+ def date_picker_component(
262
+ form: nil,
263
+ name: nil,
264
+ label: nil,
265
+ value: nil,
266
+ placeholder: nil,
267
+ size: 'md',
268
+ support_text: nil,
269
+ error: nil,
270
+ disabled: false,
271
+ html_options: {}
272
+ )
273
+ date_picker = DatePickerComponent.new(
274
+ form:,
275
+ name:,
276
+ label:,
277
+ value:,
278
+ placeholder:,
279
+ size:,
280
+ support_text:,
281
+ error:,
282
+ disabled:,
283
+ html_options:
284
+ )
285
+
286
+ render partial: 'view_components/inputs/date_picker_component/date_picker',
287
+ locals: { date_picker: }
288
+ end
289
+ end
290
+ end