view_component-form 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 (47) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +16 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +170 -0
  5. data/app/components/view_component/form/base_component.rb +53 -0
  6. data/app/components/view_component/form/button_component.rb +19 -0
  7. data/app/components/view_component/form/check_box_component.rb +27 -0
  8. data/app/components/view_component/form/collection_check_boxes_component.rb +50 -0
  9. data/app/components/view_component/form/collection_radio_buttons_component.rb +50 -0
  10. data/app/components/view_component/form/collection_select_component.rb +49 -0
  11. data/app/components/view_component/form/color_field_component.rb +9 -0
  12. data/app/components/view_component/form/date_field_component.rb +9 -0
  13. data/app/components/view_component/form/date_select_component.rb +34 -0
  14. data/app/components/view_component/form/datetime_field_component.rb +9 -0
  15. data/app/components/view_component/form/datetime_local_field_component.rb +9 -0
  16. data/app/components/view_component/form/datetime_select_component.rb +34 -0
  17. data/app/components/view_component/form/email_field_component.rb +9 -0
  18. data/app/components/view_component/form/field_component.rb +65 -0
  19. data/app/components/view_component/form/file_field_component.rb +9 -0
  20. data/app/components/view_component/form/grouped_collection_select_component.rb +57 -0
  21. data/app/components/view_component/form/label_component.rb +42 -0
  22. data/app/components/view_component/form/month_field_component.rb +9 -0
  23. data/app/components/view_component/form/number_field_component.rb +9 -0
  24. data/app/components/view_component/form/password_field_component.rb +9 -0
  25. data/app/components/view_component/form/radio_button_component.rb +27 -0
  26. data/app/components/view_component/form/range_field_component.rb +9 -0
  27. data/app/components/view_component/form/rich_text_area_component.rb +9 -0
  28. data/app/components/view_component/form/search_field_component.rb +9 -0
  29. data/app/components/view_component/form/select_component.rb +37 -0
  30. data/app/components/view_component/form/submit_component.rb +19 -0
  31. data/app/components/view_component/form/telephone_field_component.rb +9 -0
  32. data/app/components/view_component/form/text_area_component.rb +9 -0
  33. data/app/components/view_component/form/text_field_component.rb +9 -0
  34. data/app/components/view_component/form/time_field_component.rb +9 -0
  35. data/app/components/view_component/form/time_select_component.rb +34 -0
  36. data/app/components/view_component/form/time_zone_select_component.rb +36 -0
  37. data/app/components/view_component/form/url_field_component.rb +9 -0
  38. data/app/components/view_component/form/week_field_component.rb +9 -0
  39. data/lib/generators/vcf/builder/builder_generator.rb +32 -0
  40. data/lib/generators/vcf/builder/templates/builder.rb.erb +4 -0
  41. data/lib/view_component/form/builder.rb +212 -0
  42. data/lib/view_component/form/class_names_helper.rb +37 -0
  43. data/lib/view_component/form/engine.rb +15 -0
  44. data/lib/view_component/form/test_helpers.rb +29 -0
  45. data/lib/view_component/form/version.rb +7 -0
  46. data/lib/view_component/form.rb +5 -0
  47. metadata +152 -0
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ class ColorFieldComponent < FieldComponent
6
+ self.tag_klass = ActionView::Helpers::Tags::ColorField
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ class DateFieldComponent < FieldComponent
6
+ self.tag_klass = ActionView::Helpers::Tags::DateField
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ class DateSelectComponent < FieldComponent
6
+ attr_reader :html_options
7
+
8
+ def initialize(form, object_name, method_name, options = {}, html_options = {})
9
+ @html_options = html_options
10
+
11
+ super(form, object_name, method_name, options)
12
+
13
+ set_html_options!
14
+ end
15
+
16
+ def call
17
+ ActionView::Helpers::Tags::DateSelect.new(
18
+ object_name,
19
+ method_name,
20
+ @view_context,
21
+ options,
22
+ html_options
23
+ ).render
24
+ end
25
+
26
+ protected
27
+
28
+ def set_html_options!
29
+ @html_options[:class] = class_names(html_options[:class], html_class)
30
+ @html_options.delete(:class) if @html_options[:class].blank?
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ class DatetimeFieldComponent < FieldComponent
6
+ self.tag_klass = ActionView::Helpers::Tags::DatetimeField
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ class DatetimeLocalFieldComponent < FieldComponent
6
+ self.tag_klass = ActionView::Helpers::Tags::DatetimeLocalField
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ class DatetimeSelectComponent < FieldComponent
6
+ attr_reader :html_options
7
+
8
+ def initialize(form, object_name, method_name, options = {}, html_options = {})
9
+ @html_options = html_options
10
+
11
+ super(form, object_name, method_name, options)
12
+
13
+ set_html_options!
14
+ end
15
+
16
+ def call
17
+ ActionView::Helpers::Tags::DatetimeSelect.new(
18
+ object_name,
19
+ method_name,
20
+ @view_context,
21
+ options,
22
+ html_options
23
+ ).render
24
+ end
25
+
26
+ protected
27
+
28
+ def set_html_options!
29
+ @html_options[:class] = class_names(html_options[:class], html_class)
30
+ @html_options.delete(:class) if @html_options[:class].blank?
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ class EmailFieldComponent < FieldComponent
6
+ self.tag_klass = ActionView::Helpers::Tags::EmailField
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ class FieldComponent < BaseComponent
6
+ class << self
7
+ attr_accessor :tag_klass
8
+ end
9
+
10
+ attr_reader :method_name
11
+
12
+ def initialize(form, object_name, method_name, options = {})
13
+ # See: https://github.com/rails/rails/blob/83217025a171593547d1268651b446d3533e2019/actionview/lib/action_view/helpers/tags/base.rb#L13
14
+ @method_name = method_name.to_s.dup
15
+
16
+ super(form, object_name, options)
17
+ end
18
+
19
+ def call
20
+ raise "`self.tag_klass' should be defined in #{self.class.name}" unless self.class.tag_klass
21
+
22
+ self.class.tag_klass.new(object_name, method_name, @view_context, options).render
23
+ end
24
+
25
+ def method_errors
26
+ return [] unless method_errors?
27
+
28
+ @method_errors ||= object_errors.to_hash
29
+ .fetch_values(*object_method_names) { nil }
30
+ .flatten.compact
31
+ .map(&:upcase_first)
32
+ end
33
+
34
+ def method_errors?
35
+ (object_errors.keys & object_method_names).any?
36
+ end
37
+
38
+ def value
39
+ object.public_send(method_name)
40
+ end
41
+
42
+ def object_method_names
43
+ @object_method_names ||= begin
44
+ object_method_names = [method_name]
45
+ if method_name.end_with?("_id") && object.respond_to?(singular_association_method_name)
46
+ object_method_names << singular_association_method_name
47
+ elsif method_name.end_with?("_ids") && object.respond_to?(collection_association_method_name)
48
+ object_method_names << collection_association_method_name
49
+ end
50
+ object_method_names
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def singular_association_method_name
57
+ @singular_association_method_name ||= method_name.to_s.sub(/_id$/, "").to_sym
58
+ end
59
+
60
+ def collection_association_method_name
61
+ @collection_association_method_name ||= method_name.to_s.sub(/_ids$/, "").pluralize.to_sym
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ class FileFieldComponent < FieldComponent
6
+ self.tag_klass = ActionView::Helpers::Tags::FileField
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ class GroupedCollectionSelectComponent < FieldComponent
6
+ attr_reader :collection, :group_method,
7
+ :group_label_method, :option_key_method, :option_value_method,
8
+ :html_options
9
+
10
+ def initialize( # rubocop:disable Metrics/ParameterLists
11
+ form,
12
+ object_name,
13
+ method_name,
14
+ collection,
15
+ group_method,
16
+ group_label_method,
17
+ option_key_method,
18
+ option_value_method,
19
+ options = {},
20
+ html_options = {}
21
+ )
22
+ @collection = collection
23
+ @group_method = group_method
24
+ @group_label_method = group_label_method
25
+ @option_key_method = option_key_method
26
+ @option_value_method = option_value_method
27
+ @html_options = html_options
28
+
29
+ super(form, object_name, method_name, options)
30
+
31
+ set_html_options!
32
+ end
33
+
34
+ def call # rubocop:disable Metrics/MethodLength
35
+ ActionView::Helpers::Tags::GroupedCollectionSelect.new(
36
+ object_name,
37
+ method_name,
38
+ @view_context,
39
+ collection,
40
+ group_method,
41
+ group_label_method,
42
+ option_key_method,
43
+ option_value_method,
44
+ options,
45
+ html_options
46
+ ).render
47
+ end
48
+
49
+ protected
50
+
51
+ def set_html_options!
52
+ @html_options[:class] = class_names(html_options[:class], html_class)
53
+ @html_options.delete(:class) if @html_options[:class].blank?
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ class LabelComponent < FieldComponent
6
+ attr_reader :attribute_content
7
+
8
+ def initialize(form, object_name, method_name, content_or_options = nil, options = nil)
9
+ options ||= {}
10
+
11
+ content_is_options = content_or_options.is_a?(Hash)
12
+ if content_is_options
13
+ options.merge! content_or_options
14
+ @attribute_content = nil
15
+ else
16
+ @attribute_content = content_or_options
17
+ end
18
+
19
+ super(form, object_name, method_name, options)
20
+ end
21
+
22
+ def call
23
+ content_or_options = nil
24
+
25
+ content_or_options = content || attribute_content if content.present? || attribute_content.present?
26
+
27
+ ActionView::Helpers::Tags::Label.new(object_name, method_name, @view_context, content_or_options,
28
+ options).render
29
+ end
30
+
31
+ # See: https://github.com/rails/rails/blob/83217025a171593547d1268651b446d3533e2019/actionview/lib/action_view/helpers/tags/label.rb#L48
32
+ def builder
33
+ @builder ||= begin
34
+ tag_value = options.delete("value")
35
+
36
+ ActionView::Helpers::Tags::Label::LabelBuilder.new(@view_context, object_name, method_name, object, tag_value)
37
+ end
38
+ end
39
+ delegate :translation, to: :builder
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ class MonthFieldComponent < FieldComponent
6
+ self.tag_klass = ActionView::Helpers::Tags::MonthField
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ class NumberFieldComponent < FieldComponent
6
+ self.tag_klass = ActionView::Helpers::Tags::NumberField
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ class PasswordFieldComponent < FieldComponent
6
+ self.tag_klass = ActionView::Helpers::Tags::PasswordField
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ class RadioButtonComponent < FieldComponent
6
+ self.tag_klass = ActionView::Helpers::Tags::RadioButton
7
+
8
+ attr_reader :value
9
+
10
+ def initialize(form, object_name, method_name, value, options = {})
11
+ @value = value
12
+
13
+ super(form, object_name, method_name, options)
14
+ end
15
+
16
+ def call
17
+ ActionView::Helpers::Tags::RadioButton.new(
18
+ object_name,
19
+ method_name,
20
+ @view_context,
21
+ value,
22
+ options
23
+ ).render
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ class RangeFieldComponent < FieldComponent
6
+ self.tag_klass = ActionView::Helpers::Tags::RangeField
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ class RichTextAreaComponent < FieldComponent
6
+ self.tag_klass = ActionView::Helpers::Tags::ActionText
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ class SearchFieldComponent < FieldComponent
6
+ self.tag_klass = ActionView::Helpers::Tags::SearchField
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ class SelectComponent < FieldComponent
6
+ attr_reader :choices, :html_options
7
+
8
+ def initialize(form, object_name, method_name, choices = nil, options = {}, html_options = {}) # rubocop:disable Metrics/ParameterLists
9
+ @choices = choices
10
+ @html_options = html_options
11
+
12
+ super(form, object_name, method_name, options)
13
+
14
+ set_html_options!
15
+ end
16
+
17
+ def call
18
+ ActionView::Helpers::Tags::Select.new(
19
+ object_name,
20
+ method_name,
21
+ @view_context,
22
+ choices,
23
+ options,
24
+ html_options,
25
+ &content
26
+ ).render
27
+ end
28
+
29
+ protected
30
+
31
+ def set_html_options!
32
+ @html_options[:class] = class_names(html_options[:class], html_class)
33
+ @html_options.delete(:class) if @html_options[:class].blank?
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Form
5
+ class SubmitComponent < BaseComponent
6
+ attr_reader :value
7
+
8
+ def initialize(form, value, options = {})
9
+ @value = value
10
+
11
+ super(form, nil, options)
12
+ end
13
+
14
+ def call
15
+ submit_tag(value, options)
16
+ end
17
+ end
18
+ end
19
+ end