view_component-form 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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