shadcn_phlexcomponents 0.1.5 → 0.1.9

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 (181) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +14 -0
  3. data/app/javascript/controllers/accordion_controller.js +7 -16
  4. data/app/javascript/controllers/alert_dialog_controller.js +5 -141
  5. data/app/javascript/controllers/combobox_controller.js +20 -0
  6. data/app/javascript/controllers/date_picker_controller.js +199 -64
  7. data/app/javascript/controllers/date_range_picker_controller.js +289 -176
  8. data/app/javascript/controllers/dialog_controller.js +19 -64
  9. data/app/javascript/controllers/dropdown_menu_controller.js +15 -37
  10. data/app/javascript/controllers/form_field_controller.js +24 -0
  11. data/app/javascript/controllers/hover_card_controller.js +1 -22
  12. data/app/javascript/controllers/popover_controller.js +20 -31
  13. data/app/javascript/controllers/select_controller.js +32 -52
  14. data/app/javascript/controllers/sidebar_trigger_controller.js +1 -1
  15. data/app/javascript/controllers/toast_controller.js +2 -2
  16. data/app/javascript/controllers/tooltip_controller.js +1 -2
  17. data/app/javascript/shadcn_phlexcomponents.js +53 -0
  18. data/app/javascript/utils.js +184 -0
  19. data/app/stylesheets/date_picker.css +212 -0
  20. data/lib/install/install_shadcn_phlexcomponents.rb +7 -7
  21. data/lib/{components → shadcn_phlexcomponents/components/accordion}/accordion.rb +1 -1
  22. data/lib/{components → shadcn_phlexcomponents/components/accordion}/accordion_content.rb +1 -1
  23. data/lib/{components → shadcn_phlexcomponents/components/accordion}/accordion_item.rb +1 -1
  24. data/lib/{components → shadcn_phlexcomponents/components/accordion}/accordion_trigger.rb +5 -4
  25. data/lib/{components → shadcn_phlexcomponents/components/alert_dialog}/alert_dialog.rb +1 -1
  26. data/lib/{components → shadcn_phlexcomponents/components/alert_dialog}/alert_dialog_action.rb +1 -1
  27. data/lib/{components → shadcn_phlexcomponents/components/alert_dialog}/alert_dialog_action_to.rb +1 -1
  28. data/lib/{components → shadcn_phlexcomponents/components/alert_dialog}/alert_dialog_cancel.rb +1 -1
  29. data/lib/{components → shadcn_phlexcomponents/components/alert_dialog}/alert_dialog_content.rb +2 -2
  30. data/lib/{components → shadcn_phlexcomponents/components/alert_dialog}/alert_dialog_trigger.rb +2 -2
  31. data/lib/{components → shadcn_phlexcomponents/components/avatar}/avatar.rb +1 -1
  32. data/lib/{components → shadcn_phlexcomponents/components/avatar}/avatar_fallback.rb +1 -1
  33. data/lib/{components → shadcn_phlexcomponents/components/avatar}/avatar_image.rb +1 -1
  34. data/lib/{components → shadcn_phlexcomponents/components/badge}/badge.rb +1 -1
  35. data/lib/{components → shadcn_phlexcomponents/components}/base.rb +10 -0
  36. data/lib/{components → shadcn_phlexcomponents/components/breadcrumb}/breadcrumb.rb +2 -0
  37. data/lib/{components → shadcn_phlexcomponents/components/button}/button.rb +5 -5
  38. data/lib/{components → shadcn_phlexcomponents/components/checkbox}/checkbox.rb +5 -5
  39. data/lib/{components → shadcn_phlexcomponents/components/checkbox_group}/checkbox_group.rb +27 -15
  40. data/lib/{components → shadcn_phlexcomponents/components/collapsible}/collapsible.rb +1 -1
  41. data/lib/{components → shadcn_phlexcomponents/components/collapsible}/collapsible_content.rb +1 -1
  42. data/lib/{components → shadcn_phlexcomponents/components/collapsible}/collapsible_trigger.rb +2 -2
  43. data/lib/shadcn_phlexcomponents/components/date_picker/date_picker.rb +87 -0
  44. data/lib/shadcn_phlexcomponents/components/date_picker/date_picker_content.rb +45 -0
  45. data/lib/shadcn_phlexcomponents/components/date_picker/date_picker_trigger.rb +64 -0
  46. data/lib/shadcn_phlexcomponents/components/date_range_picker/date_range_picker.rb +105 -0
  47. data/lib/shadcn_phlexcomponents/components/date_range_picker/date_range_picker_content.rb +9 -0
  48. data/lib/shadcn_phlexcomponents/components/date_range_picker/date_range_picker_trigger.rb +9 -0
  49. data/lib/{components → shadcn_phlexcomponents/components/dialog}/dialog.rb +8 -8
  50. data/lib/{components → shadcn_phlexcomponents/components/dialog}/dialog_close.rb +1 -1
  51. data/lib/{components → shadcn_phlexcomponents/components/dialog}/dialog_content.rb +3 -3
  52. data/lib/{components → shadcn_phlexcomponents/components/dialog}/dialog_trigger.rb +2 -2
  53. data/lib/{components → shadcn_phlexcomponents/components/dropdown_menu}/dropdown_menu.rb +1 -1
  54. data/lib/{components → shadcn_phlexcomponents/components/dropdown_menu}/dropdown_menu_content.rb +9 -9
  55. data/lib/{components → shadcn_phlexcomponents/components/dropdown_menu}/dropdown_menu_item.rb +8 -8
  56. data/lib/{components → shadcn_phlexcomponents/components/dropdown_menu}/dropdown_menu_trigger.rb +5 -5
  57. data/lib/shadcn_phlexcomponents/components/form/form.rb +139 -0
  58. data/lib/shadcn_phlexcomponents/components/form/form_checkbox.rb +83 -0
  59. data/lib/shadcn_phlexcomponents/components/form/form_checkbox_group.rb +116 -0
  60. data/lib/shadcn_phlexcomponents/components/form/form_date_picker.rb +47 -0
  61. data/lib/shadcn_phlexcomponents/components/form/form_date_range_picker.rb +96 -0
  62. data/lib/{components → shadcn_phlexcomponents/components/form}/form_error.rb +6 -2
  63. data/lib/shadcn_phlexcomponents/components/form/form_helpers.rb +108 -0
  64. data/lib/{components → shadcn_phlexcomponents/components/form}/form_hint.rb +6 -2
  65. data/lib/shadcn_phlexcomponents/components/form/form_radio_group.rb +107 -0
  66. data/lib/shadcn_phlexcomponents/components/form/form_select.rb +65 -0
  67. data/lib/shadcn_phlexcomponents/components/form/form_switch.rb +66 -0
  68. data/lib/shadcn_phlexcomponents/components/form/form_textarea.rb +60 -0
  69. data/lib/{components → shadcn_phlexcomponents/components/hover_card}/hover_card.rb +1 -1
  70. data/lib/{components → shadcn_phlexcomponents/components/hover_card}/hover_card_content.rb +1 -1
  71. data/lib/{components → shadcn_phlexcomponents/components/hover_card}/hover_card_trigger.rb +1 -1
  72. data/lib/{components → shadcn_phlexcomponents/components/input}/input.rb +1 -1
  73. data/lib/{components → shadcn_phlexcomponents/components/loading_button}/loading_button.rb +1 -1
  74. data/lib/{components → shadcn_phlexcomponents/components/popover}/popover.rb +1 -1
  75. data/lib/{components → shadcn_phlexcomponents/components/popover}/popover_content.rb +6 -6
  76. data/lib/{components → shadcn_phlexcomponents/components/popover}/popover_trigger.rb +2 -3
  77. data/lib/{components → shadcn_phlexcomponents/components/progress}/progress.rb +3 -3
  78. data/lib/{components → shadcn_phlexcomponents/components/radio_group}/radio_group.rb +33 -7
  79. data/lib/{components → shadcn_phlexcomponents/components/radio_group}/radio_group_item.rb +7 -7
  80. data/lib/{components → shadcn_phlexcomponents/components/select}/select.rb +22 -12
  81. data/lib/{components → shadcn_phlexcomponents/components/select}/select_content.rb +6 -6
  82. data/lib/{components → shadcn_phlexcomponents/components/select}/select_group.rb +1 -1
  83. data/lib/{components → shadcn_phlexcomponents/components/select}/select_item.rb +8 -8
  84. data/lib/{components → shadcn_phlexcomponents/components/select}/select_label.rb +1 -1
  85. data/lib/{components → shadcn_phlexcomponents/components/select}/select_trigger.rb +10 -10
  86. data/lib/{components → shadcn_phlexcomponents/components/sheet}/sheet.rb +1 -1
  87. data/lib/{components → shadcn_phlexcomponents/components/sheet}/sheet_close.rb +1 -1
  88. data/lib/{components → shadcn_phlexcomponents/components/sheet}/sheet_content.rb +3 -3
  89. data/lib/{components → shadcn_phlexcomponents/components/sheet}/sheet_trigger.rb +2 -2
  90. data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar.rb +3 -3
  91. data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_trigger.rb +2 -2
  92. data/lib/{components → shadcn_phlexcomponents/components/switch}/switch.rb +4 -4
  93. data/lib/{components → shadcn_phlexcomponents/components/tabs}/tabs.rb +2 -2
  94. data/lib/{components → shadcn_phlexcomponents/components/tabs}/tabs_content.rb +1 -1
  95. data/lib/{components → shadcn_phlexcomponents/components/tabs}/tabs_trigger.rb +4 -4
  96. data/lib/{components → shadcn_phlexcomponents/components/textarea}/textarea.rb +3 -2
  97. data/lib/{components → shadcn_phlexcomponents/components/theme_switcher}/theme_switcher.rb +2 -2
  98. data/lib/{components → shadcn_phlexcomponents/components/toast}/toast.rb +7 -7
  99. data/lib/{components → shadcn_phlexcomponents/components/toast}/toast_container.rb +1 -1
  100. data/lib/{components → shadcn_phlexcomponents/components/tooltip}/tooltip.rb +3 -3
  101. data/lib/{components → shadcn_phlexcomponents/components/tooltip}/tooltip_content.rb +1 -1
  102. data/lib/{components → shadcn_phlexcomponents/components/tooltip}/tooltip_trigger.rb +1 -1
  103. data/lib/shadcn_phlexcomponents/version.rb +1 -1
  104. metadata +157 -144
  105. data/app/assets/tailwind/vanilla-calendar-pro.css +0 -466
  106. data/app/javascript/controllers/sheet_controller.js +0 -159
  107. data/lib/components/combobox.rb +0 -57
  108. data/lib/components/combobox_item.rb +0 -9
  109. data/lib/components/date_picker.rb +0 -94
  110. data/lib/components/date_range_picker.rb +0 -113
  111. data/lib/components/form.rb +0 -59
  112. /data/app/{assets/tailwind → stylesheets}/choices.css +0 -0
  113. /data/app/{assets/tailwind → stylesheets}/tailwindcss-animate.css +0 -0
  114. /data/lib/{components → shadcn_phlexcomponents/components/alert}/alert.rb +0 -0
  115. /data/lib/{components → shadcn_phlexcomponents/components/alert}/alert_description.rb +0 -0
  116. /data/lib/{components → shadcn_phlexcomponents/components/alert}/alert_title.rb +0 -0
  117. /data/lib/{components → shadcn_phlexcomponents/components/alert_dialog}/alert_dialog_description.rb +0 -0
  118. /data/lib/{components → shadcn_phlexcomponents/components/alert_dialog}/alert_dialog_footer.rb +0 -0
  119. /data/lib/{components → shadcn_phlexcomponents/components/alert_dialog}/alert_dialog_header.rb +0 -0
  120. /data/lib/{components → shadcn_phlexcomponents/components/alert_dialog}/alert_dialog_title.rb +0 -0
  121. /data/lib/{components → shadcn_phlexcomponents/components/aspect_ratio}/aspect_ratio.rb +0 -0
  122. /data/lib/{components → shadcn_phlexcomponents/components/breadcrumb}/breadcrumb_ellipsis.rb +0 -0
  123. /data/lib/{components → shadcn_phlexcomponents/components/breadcrumb}/breadcrumb_item.rb +0 -0
  124. /data/lib/{components → shadcn_phlexcomponents/components/breadcrumb}/breadcrumb_link.rb +0 -0
  125. /data/lib/{components → shadcn_phlexcomponents/components/breadcrumb}/breadcrumb_page.rb +0 -0
  126. /data/lib/{components → shadcn_phlexcomponents/components/breadcrumb}/breadcrumb_separator.rb +0 -0
  127. /data/lib/{components → shadcn_phlexcomponents/components/card}/card.rb +0 -0
  128. /data/lib/{components → shadcn_phlexcomponents/components/card}/card_content.rb +0 -0
  129. /data/lib/{components → shadcn_phlexcomponents/components/card}/card_description.rb +0 -0
  130. /data/lib/{components → shadcn_phlexcomponents/components/card}/card_footer.rb +0 -0
  131. /data/lib/{components → shadcn_phlexcomponents/components/card}/card_header.rb +0 -0
  132. /data/lib/{components → shadcn_phlexcomponents/components/card}/card_title.rb +0 -0
  133. /data/lib/{components → shadcn_phlexcomponents/components/dialog}/dialog_description.rb +0 -0
  134. /data/lib/{components → shadcn_phlexcomponents/components/dialog}/dialog_footer.rb +0 -0
  135. /data/lib/{components → shadcn_phlexcomponents/components/dialog}/dialog_header.rb +0 -0
  136. /data/lib/{components → shadcn_phlexcomponents/components/dialog}/dialog_title.rb +0 -0
  137. /data/lib/{components → shadcn_phlexcomponents/components/dropdown_menu}/dropdown_menu_item_to.rb +0 -0
  138. /data/lib/{components → shadcn_phlexcomponents/components/dropdown_menu}/dropdown_menu_label.rb +0 -0
  139. /data/lib/{components → shadcn_phlexcomponents/components/dropdown_menu}/dropdown_menu_separator.rb +0 -0
  140. /data/lib/{components → shadcn_phlexcomponents/components/form}/form_input.rb +0 -0
  141. /data/lib/{components → shadcn_phlexcomponents/components/label}/label.rb +0 -0
  142. /data/lib/{components → shadcn_phlexcomponents/components/link}/link.rb +0 -0
  143. /data/lib/{components → shadcn_phlexcomponents/components/pagination}/pagination.rb +0 -0
  144. /data/lib/{components → shadcn_phlexcomponents/components/pagination}/pagination_ellipsis.rb +0 -0
  145. /data/lib/{components → shadcn_phlexcomponents/components/pagination}/pagination_link.rb +0 -0
  146. /data/lib/{components → shadcn_phlexcomponents/components/pagination}/pagination_next.rb +0 -0
  147. /data/lib/{components → shadcn_phlexcomponents/components/pagination}/pagination_previous.rb +0 -0
  148. /data/lib/{components → shadcn_phlexcomponents/components/separator}/separator.rb +0 -0
  149. /data/lib/{components → shadcn_phlexcomponents/components/sheet}/sheet_description.rb +0 -0
  150. /data/lib/{components → shadcn_phlexcomponents/components/sheet}/sheet_footer.rb +0 -0
  151. /data/lib/{components → shadcn_phlexcomponents/components/sheet}/sheet_header.rb +0 -0
  152. /data/lib/{components → shadcn_phlexcomponents/components/sheet}/sheet_title.rb +0 -0
  153. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_container.rb +0 -0
  154. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_content.rb +0 -0
  155. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_footer.rb +0 -0
  156. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_group.rb +0 -0
  157. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_group_content.rb +0 -0
  158. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_group_label.rb +0 -0
  159. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_header.rb +0 -0
  160. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_inset.rb +0 -0
  161. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_menu.rb +0 -0
  162. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_menu_button.rb +0 -0
  163. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_menu_item.rb +0 -0
  164. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_menu_sub.rb +0 -0
  165. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_menu_sub_button.rb +0 -0
  166. /data/lib/{components → shadcn_phlexcomponents/components/sidebar}/sidebar_menu_sub_item.rb +0 -0
  167. /data/lib/{components → shadcn_phlexcomponents/components/skeleton}/skeleton.rb +0 -0
  168. /data/lib/{components → shadcn_phlexcomponents/components/table}/table.rb +0 -0
  169. /data/lib/{components → shadcn_phlexcomponents/components/table}/table_body.rb +0 -0
  170. /data/lib/{components → shadcn_phlexcomponents/components/table}/table_caption.rb +0 -0
  171. /data/lib/{components → shadcn_phlexcomponents/components/table}/table_cell.rb +0 -0
  172. /data/lib/{components → shadcn_phlexcomponents/components/table}/table_footer.rb +0 -0
  173. /data/lib/{components → shadcn_phlexcomponents/components/table}/table_head.rb +0 -0
  174. /data/lib/{components → shadcn_phlexcomponents/components/table}/table_header.rb +0 -0
  175. /data/lib/{components → shadcn_phlexcomponents/components/table}/table_row.rb +0 -0
  176. /data/lib/{components → shadcn_phlexcomponents/components/tabs}/tabs_list.rb +0 -0
  177. /data/lib/{components → shadcn_phlexcomponents/components/toast}/toast_action.rb +0 -0
  178. /data/lib/{components → shadcn_phlexcomponents/components/toast}/toast_action_to.rb +0 -0
  179. /data/lib/{components → shadcn_phlexcomponents/components/toast}/toast_content.rb +0 -0
  180. /data/lib/{components → shadcn_phlexcomponents/components/toast}/toast_description.rb +0 -0
  181. /data/lib/{components → shadcn_phlexcomponents/components/toast}/toast_title.rb +0 -0
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class FormCheckbox < Base
5
+ include FormHelpers
6
+
7
+ def initialize(
8
+ method = nil,
9
+ model: false,
10
+ object_name: nil,
11
+ value: nil,
12
+ name: nil,
13
+ id: nil,
14
+ label: nil,
15
+ error: nil,
16
+ hint: nil,
17
+ checked: nil,
18
+ **attributes
19
+ )
20
+ @method = method
21
+ @model = model
22
+ @object_name = object_name
23
+ @value = value
24
+ @model_value = model&.public_send(method)
25
+ @name = name
26
+ @id = id
27
+ @label = label
28
+ @error = error || (model ? model.errors.full_messages_for(method).first : nil)
29
+ @hint = hint
30
+ @aria_id = "form-field-#{SecureRandom.hex(5)}"
31
+ @checked = checked
32
+ super(**attributes)
33
+ end
34
+
35
+ def label_attributes(use_label_styles: false, **attributes)
36
+ attributes[:class] = [
37
+ use_label_styles ? Label::STYLES : nil,
38
+ "ml-6",
39
+ attributes[:class],
40
+ ].compact.join(" ")
41
+ attributes[:for] ||= @id
42
+ attributes
43
+ end
44
+
45
+ def hint_attributes(**attributes)
46
+ attributes[:class] = [
47
+ "ml-6",
48
+ attributes[:class],
49
+ ].compact.join(" ")
50
+ attributes
51
+ end
52
+
53
+ def view_template(&)
54
+ vanish(&)
55
+
56
+ @id ||= field_id(@object_name, @method)
57
+ @name ||= field_name(@object_name, @method)
58
+
59
+ div(class: "space-y-2") do
60
+ div(class: "flex items-top space-x-2") do
61
+ div(class: "grid gap-1.5 relative", data: label_and_hint_container_attributes) do
62
+ @attributes[:class] = "#{@attributes[:class]} -mt-[1.5px] absolute top-0 left-0"
63
+
64
+ Checkbox(
65
+ id: @id,
66
+ name: @name,
67
+ value: @value || "1",
68
+ checked: @checked || !!@model_value,
69
+ aria: aria_attributes,
70
+ disabled: @disabled,
71
+ **@attributes,
72
+ )
73
+
74
+ render_label(&)
75
+ render_hint(&)
76
+ end
77
+ end
78
+
79
+ render_error
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class FormCheckboxGroup < Base
5
+ include FormHelpers
6
+
7
+ def initialize(
8
+ method = nil,
9
+ model: false,
10
+ object_name: nil,
11
+ collection: [],
12
+ value_method: nil,
13
+ text_method: nil,
14
+ value: nil,
15
+ name: nil,
16
+ id: nil,
17
+ label: nil,
18
+ error: nil,
19
+ hint: nil,
20
+ disabled_items: nil,
21
+ **attributes
22
+ )
23
+ @method = method
24
+ @model = model
25
+ @object_name = object_name
26
+
27
+ @collection = if collection.first&.is_a?(Hash)
28
+ convert_collection_hash_to_struct(collection, value_method: value_method, text_method: text_method)
29
+ else
30
+ collection
31
+ end
32
+
33
+ @value_method = value_method
34
+ @text_method = text_method
35
+
36
+ @value = value
37
+
38
+ @model_value = if model
39
+ model_collection = model.public_send(method)
40
+
41
+ if model_collection.respond_to?(:map)
42
+ model_collection.map { |item| item.public_send(value_method) }
43
+ end
44
+ end
45
+
46
+ @name = name
47
+ @id = id
48
+ @label = label
49
+ @error = error || (model ? model.errors.full_messages_for(method).first : nil)
50
+ @hint = hint
51
+ @disabled_items = disabled_items
52
+ @aria_id = "form-field-#{SecureRandom.hex(5)}"
53
+ super(**attributes)
54
+ end
55
+
56
+ def aria_attributes
57
+ attrs = super
58
+ attrs[:labelledby] = "#{@aria_id}-label"
59
+ attrs
60
+ end
61
+
62
+ def label_attributes(use_label_styles: false, **attributes)
63
+ attrs = super(use_label_styles: use_label_styles, **attributes)
64
+ attrs[:id] = "#{@aria_id}-label"
65
+ attrs
66
+ end
67
+
68
+ def checkbox(**attributes)
69
+ @checkbox_attributes = attributes
70
+ nil
71
+ end
72
+
73
+ def checkbox_label(**attributes)
74
+ @checkbox_label_attributes = attributes
75
+ nil
76
+ end
77
+
78
+ def view_template(&)
79
+ vanish(&)
80
+
81
+ @id ||= field_id(@object_name, @method)
82
+ @name ||= field_name(@object_name, @method)
83
+
84
+ div(class: "space-y-2", data: label_and_hint_container_attributes) do
85
+ render_label(&)
86
+
87
+ CheckboxGroup(
88
+ id: @id,
89
+ name: @name,
90
+ value: @value || @model_value || [],
91
+ aria: aria_attributes,
92
+ item_id_prefix: @id,
93
+ **@attributes,
94
+ ) do |c|
95
+ c.items(
96
+ @collection,
97
+ value_method: @value_method,
98
+ text_method: @text_method,
99
+ disabled_items: @disabled_items,
100
+ ) do
101
+ if @checkbox_attributes
102
+ c.checkbox(**@checkbox_attributes)
103
+ end
104
+
105
+ if @checkbox_label_attributes
106
+ c.label(**@checkbox_label_attributes)
107
+ end
108
+ end
109
+ end
110
+
111
+ render_hint(&)
112
+ render_error
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class FormDatePicker < Base
5
+ include FormHelpers
6
+
7
+ def initialize(
8
+ method = nil,
9
+ model: false,
10
+ object_name: nil,
11
+ value: nil,
12
+ name: nil,
13
+ id: nil,
14
+ label: nil,
15
+ error: nil,
16
+ hint: nil,
17
+ **attributes
18
+ )
19
+ @method = method
20
+ @model = model
21
+ @object_name = object_name
22
+ @value = value
23
+ @model_value = model&.public_send(method)
24
+ @name = name
25
+ @id = id
26
+ @label = label
27
+ @error = error || (model ? model.errors.full_messages_for(method).first : nil)
28
+ @hint = hint
29
+ @aria_id = "form-field-#{SecureRandom.hex(5)}"
30
+ super(**attributes)
31
+ end
32
+
33
+ def view_template(&)
34
+ vanish(&)
35
+
36
+ @id ||= field_id(@object_name, @method)
37
+ @name ||= field_name(@object_name, @method)
38
+
39
+ div(class: "space-y-2", data: label_and_hint_container_attributes) do
40
+ render_label(&)
41
+ DatePicker(id: @id, name: @name, value: @value || @model_value, aria: aria_attributes, **@attributes)
42
+ render_hint(&)
43
+ render_error
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class FormDateRangePicker < Base
5
+ include FormHelpers
6
+
7
+ def initialize(
8
+ start_date_method,
9
+ end_date_method,
10
+ model: false,
11
+ object_name: nil,
12
+ start_date: nil,
13
+ end_date: nil,
14
+ start_date_name: nil,
15
+ end_date_name: nil,
16
+ id: nil,
17
+ label: nil,
18
+ start_date_error: nil,
19
+ end_date_error: nil,
20
+ hint: nil,
21
+ **attributes
22
+ )
23
+ @start_date_method = start_date_method
24
+ @end_date_method = end_date_method
25
+ @model = model
26
+ @object_name = object_name
27
+ @start_date = start_date
28
+ @end_date = start_date
29
+ @start_date_model_value = model&.public_send(start_date_method)
30
+ @end_date_model_value = model&.public_send(end_date_method)
31
+ @start_date_name = start_date_name
32
+ @end_date_name = end_date_name
33
+ @id = id
34
+ @label = label
35
+ @start_date_error = start_date_error || (model ? model.errors.full_messages_for(start_date_method).first : nil)
36
+ @end_date_error = end_date_error || (model ? model.errors.full_messages_for(end_date_method).first : nil)
37
+ @error = (@start_date_error || @end_date_error).present?
38
+ @hint = hint
39
+ @aria_id = "form-field-#{SecureRandom.hex(5)}"
40
+ super(**attributes)
41
+ end
42
+
43
+ def render_label(&)
44
+ # It's currently not possible to separate the content of the yield in Phlex.
45
+ # So we use Javascript to remove the duplicated hint or label.
46
+ if @yield_label && @yield_hint
47
+ div(data: { remove_hint: true }, &)
48
+ elsif @yield_label
49
+ yield
50
+ elsif @label
51
+ attrs = label_attributes(use_label_styles: false)
52
+ Label(**attrs) { @label }
53
+ elsif @label != false
54
+ attrs = label_attributes(use_label_styles: true)
55
+ rails_label(@object_name, [@start_date_method, @end_date_method].to_sentence, nil, **attrs)
56
+ end
57
+ end
58
+
59
+ def render_error
60
+ if @start_date_error && @end_date_error
61
+ FormError(nil, aria_id: @aria_id) do
62
+ span { @start_date_error }
63
+ br
64
+ span { @end_date_error }
65
+ end
66
+ elsif @start_date_error
67
+ FormError(@start_date_error, aria_id: @aria_id)
68
+ elsif @end_date_error
69
+ FormError(@end_date_error, aria_id: @aria_id)
70
+ end
71
+ end
72
+
73
+ def view_template(&)
74
+ vanish(&)
75
+
76
+ @id ||= field_id(@object_name, @start_date_method)
77
+ @start_date_name ||= field_name(@object_name, @start_date_method)
78
+ @end_date_name ||= field_name(@object_name, @end_date_method)
79
+
80
+ div(class: "space-y-2", data: label_and_hint_container_attributes) do
81
+ render_label(&)
82
+ DateRangePicker(
83
+ id: @id,
84
+ start_date_name: @start_date_name,
85
+ end_date_name: @end_date_name,
86
+ start_date: @start_date || @start_date_model_value,
87
+ end_date: @end_date || @end_date_model_value,
88
+ aria: aria_attributes,
89
+ **@attributes,
90
+ )
91
+ render_hint(&)
92
+ render_error
93
+ end
94
+ end
95
+ end
96
+ end
@@ -4,14 +4,18 @@ module ShadcnPhlexcomponents
4
4
  class FormError < Base
5
5
  STYLES = "text-[0.8rem] font-medium text-destructive"
6
6
 
7
- def initialize(message: nil, aria_id: nil, **attributes)
7
+ def initialize(message, aria_id: nil, **attributes)
8
8
  @message = message
9
9
  @id = aria_id ? "#{aria_id}-message" : nil
10
10
  super(**attributes)
11
11
  end
12
12
 
13
13
  def view_template(&)
14
- p(id: @id, **@attributes) { @message }
14
+ if @message
15
+ p(id: @id, **@attributes) { @message }
16
+ else
17
+ p(id: @id, **@attributes, &)
18
+ end
15
19
  end
16
20
  end
17
21
  end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ module FormHelpers
5
+ module AliasedLabel
6
+ include Phlex::Rails::Helpers::Label
7
+
8
+ alias_method :rails_label, :label
9
+ end
10
+
11
+ include AliasedLabel
12
+ include Phlex::Rails::Helpers::FieldID
13
+ include Phlex::Rails::Helpers::FieldName
14
+
15
+ def label(text = nil, **attributes, &)
16
+ @yield_label = true
17
+ attrs = label_attributes(use_label_styles: false, **attributes)
18
+
19
+ if text
20
+ Label(**attrs) { text }
21
+ else
22
+ Label(**attrs, &)
23
+ end
24
+ end
25
+
26
+ def hint(text = nil, **attributes, &)
27
+ @yield_hint = true
28
+ attrs = hint_attributes(**attributes)
29
+
30
+ if text
31
+ FormHint(text, **attrs)
32
+ else
33
+ FormHint(**attrs, &)
34
+ end
35
+ end
36
+
37
+ def render_label(&)
38
+ # It's currently not possible to separate the content of the yield in Phlex.
39
+ # So we use Javascript to remove the duplicated hint or label.
40
+ if @yield_label && @yield_hint
41
+ div(data: { remove_hint: true }, &)
42
+ elsif @yield_label
43
+ yield
44
+ elsif @label
45
+ attrs = label_attributes(use_label_styles: false)
46
+ Label(**attrs) { @label }
47
+ elsif @label != false
48
+ attrs = label_attributes(use_label_styles: true)
49
+ rails_label(@object_name, @method, nil, **attrs)
50
+ end
51
+ end
52
+
53
+ def render_hint(&)
54
+ # It's currently not possible to separate the content of the yield in Phlex.
55
+ # So we use Javascript to remove the duplicated hint or label.
56
+ if @yield_label && @yield_hint
57
+ div(data: { remove_label: true }, &)
58
+ elsif @yield_hint
59
+ yield
60
+ elsif @hint
61
+ attrs = hint_attributes
62
+ FormHint(@hint, aria_id: @aria_id, **attrs)
63
+ end
64
+ end
65
+
66
+ def render_error
67
+ if @error
68
+ FormError(@error, aria_id: @aria_id)
69
+ end
70
+ end
71
+
72
+ def label_attributes(use_label_styles: false, **attributes)
73
+ attributes[:class] = [
74
+ use_label_styles ? Label::STYLES : nil,
75
+ @error ? "text-destructive" : nil,
76
+ attributes[:class],
77
+ ].compact.join(" ")
78
+ attributes[:for] ||= @id
79
+ attributes
80
+ end
81
+
82
+ def hint_attributes(**attributes)
83
+ attributes
84
+ end
85
+
86
+ def label_and_hint_container_attributes
87
+ {
88
+ controller: @yield_label && @yield_hint ? "form-field" : nil,
89
+ }.compact
90
+ end
91
+
92
+ def aria_attributes
93
+ {
94
+ describedby: describedby,
95
+ invalid: @error.present?,
96
+ }.compact
97
+ end
98
+
99
+ def describedby
100
+ return if !@hint && !@error
101
+
102
+ [
103
+ @hint ? "#{@aria_id}-description" : nil,
104
+ @error ? "#{@aria_id}-message" : nil,
105
+ ].compact.join(" ")
106
+ end
107
+ end
108
+ end
@@ -4,14 +4,18 @@ module ShadcnPhlexcomponents
4
4
  class FormHint < Base
5
5
  STYLES = "text-[0.8rem] text-muted-foreground"
6
6
 
7
- def initialize(message: nil, aria_id: nil, **attributes)
7
+ def initialize(message = nil, aria_id: nil, **attributes)
8
8
  @message = message
9
9
  @id = aria_id ? "#{aria_id}-description" : nil
10
10
  super(**attributes)
11
11
  end
12
12
 
13
13
  def view_template(&)
14
- p(id: @id, **@attributes) { @message }
14
+ if @message
15
+ p(id: @id, **@attributes) { @message }
16
+ else
17
+ p(id: @id, **@attributes, &)
18
+ end
15
19
  end
16
20
  end
17
21
  end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class FormRadioGroup < Base
5
+ include FormHelpers
6
+
7
+ def initialize(
8
+ method = nil,
9
+ model: false,
10
+ object_name: nil,
11
+ collection: [],
12
+ value_method: nil,
13
+ text_method: nil,
14
+ value: nil,
15
+ name: nil,
16
+ id: nil,
17
+ label: nil,
18
+ error: nil,
19
+ hint: nil,
20
+ disabled_items: nil,
21
+ **attributes
22
+ )
23
+ @method = method
24
+ @model = model
25
+ @object_name = object_name
26
+
27
+ @collection = if collection.first&.is_a?(Hash)
28
+ convert_collection_hash_to_struct(collection, value_method: value_method, text_method: text_method)
29
+ else
30
+ collection
31
+ end
32
+
33
+ @value_method = value_method
34
+ @text_method = text_method
35
+ @value = value
36
+ @model_value = model&.public_send(method)
37
+ @name = name
38
+ @id = id
39
+ @label = label
40
+ @error = error || (model ? model.errors.full_messages_for(method).first : nil)
41
+ @hint = hint
42
+ @disabled_items = disabled_items
43
+ @aria_id = "form-field-#{SecureRandom.hex(5)}"
44
+ super(**attributes)
45
+ end
46
+
47
+ def aria_attributes
48
+ attrs = super
49
+ attrs[:labelledby] = "#{@aria_id}-label"
50
+ attrs
51
+ end
52
+
53
+ def label_attributes(use_label_styles: false, **attributes)
54
+ attrs = super(use_label_styles: use_label_styles, **attributes)
55
+ attrs[:id] = "#{@aria_id}-label"
56
+ attrs
57
+ end
58
+
59
+ def radio(**attributes)
60
+ @radio_attributes = attributes
61
+ nil
62
+ end
63
+
64
+ def radio_label(**attributes)
65
+ @radio_label_attributes = attributes
66
+ nil
67
+ end
68
+
69
+ def view_template(&)
70
+ vanish(&)
71
+
72
+ @id ||= field_id(@object_name, @method)
73
+ @name ||= field_name(@object_name, @method)
74
+
75
+ div(class: "space-y-2", data: label_and_hint_container_attributes) do
76
+ render_label(&)
77
+
78
+ RadioGroup(
79
+ name: @name,
80
+ id: @id,
81
+ value: @value || @model_value,
82
+ aria: aria_attributes,
83
+ item_id_prefix: @id,
84
+ **@attributes,
85
+ ) do |c|
86
+ c.items(
87
+ @collection,
88
+ value_method: @value_method,
89
+ text_method: @text_method,
90
+ disabled_items: @disabled_items,
91
+ ) do
92
+ if @radio_attributes
93
+ c.radio(**@radio_attributes)
94
+ end
95
+
96
+ if @radio_label_attributes
97
+ c.label(**@radio_label_attributes)
98
+ end
99
+ end
100
+ end
101
+
102
+ render_hint(&)
103
+ render_error
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class FormSelect < Base
5
+ include FormHelpers
6
+
7
+ def initialize(
8
+ method = nil,
9
+ model: false,
10
+ object_name: nil,
11
+ collection: [],
12
+ value_method: nil,
13
+ text_method: nil,
14
+ value: nil,
15
+ name: nil,
16
+ id: nil,
17
+ label: nil,
18
+ error: nil,
19
+ hint: nil,
20
+ disabled_items: nil,
21
+ **attributes
22
+ )
23
+ @method = method
24
+ @model = model
25
+ @object_name = object_name
26
+
27
+ @collection = if collection.first&.is_a?(Hash)
28
+ convert_collection_hash_to_struct(collection, value_method: value_method, text_method: text_method)
29
+ else
30
+ collection
31
+ end
32
+
33
+ @value_method = value_method
34
+ @text_method = text_method
35
+ @value = value
36
+ @model_value = model&.public_send(method)
37
+ @name = name
38
+ @id = id
39
+ @label = label
40
+ @error = error || (model ? model.errors.full_messages_for(method).first : nil)
41
+ @hint = hint
42
+ @disabled_items = disabled_items
43
+ @aria_id = "form-field-#{SecureRandom.hex(5)}"
44
+ super(**attributes)
45
+ end
46
+
47
+ def view_template(&)
48
+ vanish(&)
49
+
50
+ @id ||= field_id(@object_name, @method)
51
+ @name ||= field_name(@object_name, @method)
52
+
53
+ div(class: "space-y-2", data: label_and_hint_container_attributes) do
54
+ render_label(&)
55
+
56
+ Select(id: @id, name: @name, value: @value || @model_value, aria: aria_attributes, **@attributes) do |s|
57
+ s.items(@collection, value_method: @value_method, text_method: @text_method, disabled_items: @disabled_items)
58
+ end
59
+
60
+ render_hint(&)
61
+ render_error
62
+ end
63
+ end
64
+ end
65
+ end