rails_bootstrap_form 0.2.2 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eeb7afe12b186dfa741279347931a85c33ff4950dcb691d6089e18767d5edb80
4
- data.tar.gz: 18787c6cfd1ad0c3156f1611395551fb5c9c41d1e17983ac1393b7987d099455
3
+ metadata.gz: 54148096404aa5a60bc550aca63ac09e15c0ec5b6bc9de993bd908879d366908
4
+ data.tar.gz: 85a7d48bf6ccf530828395265f9aa41db7be3b1bf9fc6a8f83455614449ec02a
5
5
  SHA512:
6
- metadata.gz: 7de97d7da63f5742b0db6816e908335540c1b66eaab7509bca8257005dc30e7bb2dd7f1974d3f7d0cf45dcdb909e9644c4cd29bddd7de6450bad05e2216f7c64
7
- data.tar.gz: 97997858453d5b926fb23a8a64fe36294d5cf08c7d164a8a984eb5b42ee5d956451908567d4f3473bf1cd369b2570119bb211c8071f26096e78e3b90852bdc54
6
+ metadata.gz: d9569aeb686d7bef2a2c15018c46e14413c35ecb9eb18ce784cc4b074dcfdc2e5205e583cbf9ad85a6d98da8ab2939af772903c12c5d1a2d3bc0812bd908bf4f
7
+ data.tar.gz: 6b7222a2477195f38db5b63aeddecf28777e8f1de3dcb17ddbcd3126c747aa61903d411bad1341976590ccfb92e1cab07c93dcb31c4e49e7743b607478acce8b
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rails_bootstrap_form (0.2.2)
4
+ rails_bootstrap_form (0.3.0)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3
+ <svg version="1.1" id="icon-exclamation-triangle" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24" fill="#cf222e">
4
+ <path d="M12,16a1,1,0,1,0,1,1A1,1,0,0,0,12,16Zm10.67,1.47-8.05-14a3,3,0,0,0-5.24,0l-8,14A3,3,0,0,0,3.94,22H20.06a3,3,0,0,0,2.61-4.53Zm-1.73,2a1,1,0,0,1-.88.51H3.94a1,1,0,0,1-.88-.51,1,1,0,0,1,0-1l8-14a1,1,0,0,1,1.78,0l8.05,14A1,1,0,0,1,20.94,19.49ZM12,8a1,1,0,0,0-1,1v4a1,1,0,0,0,2,0V9A1,1,0,0,0,12,8Z" />
5
+ </svg>
@@ -1 +1,16 @@
1
-
1
+ label.is-invalid, .invalid-feedback {
2
+ color: var(--bs-danger);
3
+ }
4
+ label.required::after {
5
+ color: var(--bs-danger);
6
+ content: "*";
7
+ padding-left: .25rem;
8
+ top: -2px;
9
+ font-weight: bolder;
10
+ }
11
+ .form-control.is-invalid, .form-select.is-invalid {
12
+ background-image: url("exclamation-triangle.svg") !important;
13
+ background-repeat: no-repeat !important;
14
+ background-position: right 0.5rem center, center right 2rem !important;
15
+ background-size: 24px 24px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem) !important;
16
+ }
@@ -7,6 +7,7 @@ module RailsBootstrapForm
7
7
 
8
8
  include RailsBootstrapForm::FieldWrapperBuilder
9
9
  include RailsBootstrapForm::Components
10
+ include RailsBootstrapForm::InputGroupBuilder
10
11
  include RailsBootstrapForm::Inputs
11
12
 
12
13
  delegate :capture, :concat, :tag, to: :@template
@@ -35,12 +35,15 @@ module RailsBootstrapForm
35
35
  attr_accessor :help_text
36
36
 
37
37
  # An option to override automatically generated label text.
38
+ # Default is `nil`.
38
39
  attr_accessor :label_text
39
40
 
40
41
  # An option to custmize whether the label is to be displayed or not.
42
+ # Default is `false`.
41
43
  attr_accessor :skip_label
42
44
 
43
45
  # An option to customize whether the label is only visible to screen readers.
46
+ # Default is `false`.
44
47
  attr_accessor :hide_label
45
48
 
46
49
  # The CSS class that will be used when the label is only accessible by screen
@@ -52,9 +55,33 @@ module RailsBootstrapForm
52
55
  attr_accessor :label_class
53
56
 
54
57
  # An additional CSS class that will be added along with the existing
55
- # `label_class` of the label. Default is nil.
58
+ # `label_class` of the label. Default is `nil`.
56
59
  attr_accessor :additional_label_class
57
60
 
61
+ # Input group specific options. Input groups allow prepending and appending
62
+ # arbitrary html or text to the field.
63
+ #
64
+ # Example:
65
+ #
66
+ # form.text_field :dollars, bootstrap_form: {input_group: {prepend: "$", append: ".00"}}
67
+ # form.text_field :search, bootstrap_form: {input_group: {append: button_tag("Go", type: :submit, class: "btn btn-secondary")}}
68
+ #
69
+ # Raw or HTML content to be prepended to the field.
70
+ # Default is `nil`.
71
+ attr_accessor :prepend
72
+
73
+ # Raw or HTML content to be appended to the field.
74
+ # Default is `nil`.
75
+ attr_accessor :append
76
+
77
+ # Append additional CSS class added to the input group wrapper.
78
+ # Default is `nil`.
79
+ attr_accessor :additional_input_group_class
80
+
81
+ # Option to control whether the field should have a floating label.
82
+ # Default is false.
83
+ attr_accessor :floating
84
+
58
85
  def initialize(options = {})
59
86
  set_defaults
60
87
  set_bootstrap_form_options(options)
@@ -105,12 +132,14 @@ module RailsBootstrapForm
105
132
 
106
133
  @help_text = nil
107
134
 
108
- @label_text = ""
135
+ @label_text = nil
109
136
  @skip_label = false
110
137
  @hide_label = false
111
138
  @hide_class = "visually-hidden"
112
139
  @label_class = "form-label"
113
140
  @additional_label_class = nil
141
+
142
+ @floating = false
114
143
  end
115
144
 
116
145
  private :set_defaults
@@ -0,0 +1,67 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # -*- frozen_string_literal: true -*-
3
+ # -*- warn_indent: true -*-
4
+
5
+ module RailsBootstrapForm
6
+ module Components
7
+ module Errors
8
+ extend ActiveSupport::Concern
9
+
10
+ def self.included(base_class)
11
+ def is_invalid?(attribute)
12
+ (attribute && object.respond_to?(:errors) && object.errors[attribute].any?) ||
13
+ has_association_error?(attribute)
14
+ end
15
+
16
+ def input_with_error(attribute, &block)
17
+ input = capture(&block)
18
+ input << generate_error(attribute)
19
+ input
20
+ end
21
+
22
+ def generate_error(attribute)
23
+ if is_invalid?(attribute)
24
+ error_text = error_messages(attribute)
25
+ error_klass = "invalid-feedback"
26
+
27
+ tag.div(error_text, class: error_klass)
28
+ end
29
+ end
30
+
31
+ def has_association_error?(attribute)
32
+ object.class.reflections.any? do |association_name, association|
33
+ next unless is_belongs_to_association?(association)
34
+ next unless is_association_same?(attribute, association)
35
+
36
+ object.errors[association_name].any?
37
+ end
38
+ end
39
+
40
+ def error_messages(attribute)
41
+ messages = object.errors[attribute]
42
+
43
+ object.class.reflections.each do |association_name, association|
44
+ next unless is_belongs_to_association?(association)
45
+ next unless is_association_same?(attribute, association)
46
+
47
+ messages << object.errors[association_name]
48
+ end
49
+
50
+ messages.flatten.to_sentence
51
+ end
52
+
53
+ def is_belongs_to_association?(association)
54
+ association.is_a?(ActiveRecord::Reflection::BelongsToReflection)
55
+ end
56
+
57
+ def is_association_same?(attribute, association)
58
+ (association.foreign_key == attribute.to_s)
59
+ end
60
+
61
+ private :is_invalid?, :input_with_error, :generate_error,
62
+ :has_association_error?, :error_messages,
63
+ :is_belongs_to_association?, :is_association_same?
64
+ end
65
+ end
66
+ end
67
+ end
@@ -20,6 +20,8 @@ module RailsBootstrapForm
20
20
  def label_classes(attribute, bootstrap_options)
21
21
  classes = [bootstrap_options.label_class, bootstrap_options.additional_label_class]
22
22
  classes << bootstrap_options.hide_class if bootstrap_options.hide_label
23
+ classes << "required" if is_attribute_required?(attribute)
24
+ classes << "is-invalid" if is_invalid?(attribute)
23
25
  classes.flatten.compact
24
26
  end
25
27
 
@@ -0,0 +1,64 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # -*- frozen_string_literal: true -*-
3
+ # -*- warn_indent: true -*-
4
+
5
+ module RailsBootstrapForm
6
+ module Components
7
+ module RequiredField
8
+ extend ActiveSupport::Concern
9
+
10
+ def self.included(base_class)
11
+ def is_field_required?(attribute, options)
12
+ return false unless attribute
13
+
14
+ if options.key?(:required)
15
+ options[:required]
16
+ else
17
+ is_attribute_required?(attribute)
18
+ end
19
+ end
20
+
21
+ def required_field_options(attribute, options)
22
+ required = is_field_required?(attribute, options)
23
+
24
+ {}.tap do |option|
25
+ option[:aria] = {required: true} if required
26
+ option[:required] = required
27
+ end
28
+ end
29
+
30
+ def is_attribute_required?(attribute)
31
+ return false unless attribute
32
+
33
+ target = object.instance_of?(Class) ? object : object.class
34
+ return false unless target.respond_to?(:validators_on)
35
+
36
+ has_presence_validator?(target_validators(target, attribute)) ||
37
+ is_required_association?(target, attribute)
38
+ end
39
+
40
+ def target_validators(target, attribute)
41
+ target.validators_on(attribute).map(&:class)
42
+ end
43
+
44
+ def has_presence_validator?(target_validators)
45
+ target_validators.include?(ActiveModel::Validations::PresenceValidator) ||
46
+ (defined?(ActiveRecord::Validations::PresenceValidator) &&
47
+ target_validators.include?(ActiveRecord::Validations::PresenceValidator))
48
+ end
49
+
50
+ def is_required_association?(target, attribute)
51
+ target.reflections.find do |name, a|
52
+ next unless a.is_a?(ActiveRecord::Reflection::BelongsToReflection)
53
+ next unless a.foreign_key == attribute.to_s
54
+
55
+ has_presence_validator?(target_validators(target, name))
56
+ end
57
+ end
58
+
59
+ private :is_field_required?, :required_field_options, :target_validators,
60
+ :has_presence_validator?, :is_required_association?
61
+ end
62
+ end
63
+ end
64
+ end
@@ -8,8 +8,12 @@ module RailsBootstrapForm
8
8
 
9
9
  autoload :HelpText
10
10
  autoload :Labels
11
+ autoload :RequiredField
12
+ autoload :Errors
11
13
 
12
14
  include HelpText
13
15
  include Labels
16
+ include RequiredField
17
+ include Errors
14
18
  end
15
19
  end
@@ -16,10 +16,24 @@ module RailsBootstrapForm
16
16
  label = label(attribute, bootstrap_options)
17
17
  help_text = help_text(attribute, bootstrap_options)
18
18
 
19
- tag.div(class: field_wrapper_classes) do
20
- concat(label)
21
- concat(capture(&block))
22
- concat(help_text)
19
+ if bootstrap_options.floating
20
+ tag.div(class: field_wrapper_classes) do
21
+ concat(input_group_wrapper(attribute, bootstrap_options) do
22
+ tag.div(class: floating_label_classes(attribute)) do
23
+ concat(capture(&block))
24
+ concat(label)
25
+ end
26
+ end)
27
+ concat(help_text)
28
+ end
29
+ else
30
+ tag.div(class: field_wrapper_classes) do
31
+ concat(label)
32
+ concat(input_group_wrapper(attribute, bootstrap_options) do
33
+ capture(&block)
34
+ end)
35
+ concat(help_text)
36
+ end
23
37
  end
24
38
  end
25
39
 
@@ -42,12 +56,28 @@ module RailsBootstrapForm
42
56
  bootstrap_options.field_class,
43
57
  bootstrap_options.additional_field_class
44
58
  ]
59
+ field_classes << "is-invalid" if is_invalid?(attribute)
60
+
45
61
  css_options[:class] = field_classes.flatten.compact
46
62
 
63
+ css_options.merge!(required_field_options(attribute, options))
64
+
65
+ if bootstrap_options.floating
66
+ css_options[:placeholder] ||= label_text(attribute, bootstrap_options)
67
+ end
68
+
47
69
  css_options
48
70
  end
49
71
 
72
+ def floating_label_classes(attribute)
73
+ classes = Array("form-floating")
74
+ # Floating label fields with input group requires `is-invalid` class in
75
+ # order to display error messages.
76
+ classes << "is-invalid" if is_invalid?(attribute)
77
+ classes
78
+ end
79
+
50
80
  private :field_wrapper, :field_wrapper_classes, :form_wrapper_default_class,
51
- :field_css_options
81
+ :field_css_options, :floating_label_classes
52
82
  end
53
83
  end
@@ -0,0 +1,49 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # -*- frozen_string_literal: true -*-
3
+ # -*- warn_indent: true -*-
4
+
5
+ module RailsBootstrapForm
6
+ module InputGroupBuilder
7
+ extend ActiveSupport::Concern
8
+
9
+ def self.included(base_class)
10
+ def input_group_wrapper(attribute, bootstrap_options, &block)
11
+ input = capture(&block) || ActiveSupport::SafeBuffer.new
12
+
13
+ prepend = attach_input(bootstrap_options, :prepend)
14
+ append = attach_input(bootstrap_options, :append)
15
+
16
+ input = prepend + input + append
17
+ input += generate_error(attribute)
18
+
19
+ input = tag.div(input, class: input_group_classes(attribute, bootstrap_options))
20
+
21
+ input
22
+ end
23
+
24
+ def input_group_classes(attribute, bootstrap_options)
25
+ classes = ["input-group", bootstrap_options.additional_input_group_class]
26
+ # Require `has-validation` class if field has errors.
27
+ classes << "has-validation" if is_invalid?(attribute)
28
+ classes.flatten.compact
29
+ end
30
+
31
+ def attach_input(bootstrap_options, key)
32
+ tags = [*bootstrap_options.send(key)].map do |item|
33
+ input_group_content(item)
34
+ end
35
+
36
+ ActiveSupport::SafeBuffer.new(tags.join)
37
+ end
38
+
39
+ def input_group_content(content)
40
+ return content if /button|submit/.match?(content)
41
+
42
+ tag.span(content.html_safe, class: "input-group-text")
43
+ end
44
+
45
+ private :input_group_wrapper, :input_group_classes, :attach_input,
46
+ :input_group_content
47
+ end
48
+ end
49
+ end
@@ -3,6 +3,6 @@
3
3
  # -*- warn_indent: true -*-
4
4
 
5
5
  module RailsBootstrapForm
6
- VERSION = "0.2.2".freeze
6
+ VERSION = "0.3.0".freeze
7
7
  REQUIRED_RAILS_VERSION = "~> 7.0".freeze
8
8
  end
@@ -13,8 +13,9 @@ module RailsBootstrapForm
13
13
  autoload :Configuration
14
14
  autoload :BootstrapFormOptions
15
15
  autoload :BootstrapFormBuilder
16
- autoload :FieldWrapperBuilder
17
16
  autoload :Components
17
+ autoload :FieldWrapperBuilder
18
+ autoload :InputGroupBuilder
18
19
  autoload :Inputs
19
20
  end
20
21
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_bootstrap_form
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Harshal LADHE (shivam091)
@@ -40,6 +40,7 @@ files:
40
40
  - LICENSE.txt
41
41
  - README.md
42
42
  - Rakefile
43
+ - app/assets/images/exclamation-triangle.svg
43
44
  - app/assets/stylesheets/rails_bootstrap_form.css
44
45
  - demo/.byebug_history
45
46
  - demo/.ruby-version
@@ -108,11 +109,14 @@ files:
108
109
  - lib/rails_bootstrap_form/bootstrap_form_builder.rb
109
110
  - lib/rails_bootstrap_form/bootstrap_form_options.rb
110
111
  - lib/rails_bootstrap_form/components.rb
112
+ - lib/rails_bootstrap_form/components/errors.rb
111
113
  - lib/rails_bootstrap_form/components/help_text.rb
112
114
  - lib/rails_bootstrap_form/components/labels.rb
115
+ - lib/rails_bootstrap_form/components/required_field.rb
113
116
  - lib/rails_bootstrap_form/configuration.rb
114
117
  - lib/rails_bootstrap_form/engine.rb
115
118
  - lib/rails_bootstrap_form/field_wrapper_builder.rb
119
+ - lib/rails_bootstrap_form/input_group_builder.rb
116
120
  - lib/rails_bootstrap_form/inputs.rb
117
121
  - lib/rails_bootstrap_form/version.rb
118
122
  - sig/rails_bootstrap_form.rbs