Skip to content

Commit

Permalink
Merge pull request #6 from shivam091/0.3.0
Browse files Browse the repository at this point in the history
0.3.0
  • Loading branch information
shivam091 committed May 15, 2023
2 parents fdf4fb9 + 37a3ed3 commit a1fc596
Show file tree
Hide file tree
Showing 14 changed files with 203 additions and 12 deletions.
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
rails_bootstrap_form (0.2.3)
rails_bootstrap_form (0.3.0)

GEM
remote: http://rubygems.org/
Expand Down
5 changes: 5 additions & 0 deletions app/assets/images/exclamation-triangle.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions app/assets/stylesheets/rails_bootstrap_form.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,9 @@ label.required::after {
top: -2px;
font-weight: bolder;
}
.form-control.is-invalid, .form-select.is-invalid {
background-image: url("exclamation-triangle.svg") !important;
background-repeat: no-repeat !important;
background-position: right 0.5rem center, center right 2rem !important;
background-size: 24px 24px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem) !important;
}
3 changes: 2 additions & 1 deletion lib/rails_bootstrap_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ module RailsBootstrapForm
autoload :Configuration
autoload :BootstrapFormOptions
autoload :BootstrapFormBuilder
autoload :FieldWrapperBuilder
autoload :Components
autoload :FieldWrapperBuilder
autoload :InputGroupBuilder
autoload :Inputs
end

Expand Down
1 change: 1 addition & 0 deletions lib/rails_bootstrap_form/bootstrap_form_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class BootstrapFormBuilder < ActionView::Helpers::FormBuilder

include RailsBootstrapForm::FieldWrapperBuilder
include RailsBootstrapForm::Components
include RailsBootstrapForm::InputGroupBuilder
include RailsBootstrapForm::Inputs

delegate :capture, :concat, :tag, to: :@template
Expand Down
33 changes: 31 additions & 2 deletions lib/rails_bootstrap_form/bootstrap_form_options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,15 @@ class BootstrapFormOptions
attr_accessor :help_text

# An option to override automatically generated label text.
# Default is `nil`.
attr_accessor :label_text

# An option to custmize whether the label is to be displayed or not.
# Default is `false`.
attr_accessor :skip_label

# An option to customize whether the label is only visible to screen readers.
# Default is `false`.
attr_accessor :hide_label

# The CSS class that will be used when the label is only accessible by screen
Expand All @@ -52,9 +55,33 @@ class BootstrapFormOptions
attr_accessor :label_class

# An additional CSS class that will be added along with the existing
# `label_class` of the label. Default is nil.
# `label_class` of the label. Default is `nil`.
attr_accessor :additional_label_class

# Input group specific options. Input groups allow prepending and appending
# arbitrary html or text to the field.
#
# Example:
#
# form.text_field :dollars, bootstrap_form: {input_group: {prepend: "$", append: ".00"}}
# form.text_field :search, bootstrap_form: {input_group: {append: button_tag("Go", type: :submit, class: "btn btn-secondary")}}
#
# Raw or HTML content to be prepended to the field.
# Default is `nil`.
attr_accessor :prepend

# Raw or HTML content to be appended to the field.
# Default is `nil`.
attr_accessor :append

# Append additional CSS class added to the input group wrapper.
# Default is `nil`.
attr_accessor :additional_input_group_class

# Option to control whether the field should have a floating label.
# Default is false.
attr_accessor :floating

def initialize(options = {})
set_defaults
set_bootstrap_form_options(options)
Expand Down Expand Up @@ -105,12 +132,14 @@ def set_defaults

@help_text = nil

@label_text = ""
@label_text = nil
@skip_label = false
@hide_label = false
@hide_class = "visually-hidden"
@label_class = "form-label"
@additional_label_class = nil

@floating = false
end

private :set_defaults
Expand Down
2 changes: 2 additions & 0 deletions lib/rails_bootstrap_form/components.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ module Components
autoload :HelpText
autoload :Labels
autoload :RequiredField
autoload :Errors

include HelpText
include Labels
include RequiredField
include Errors
end
end
67 changes: 67 additions & 0 deletions lib/rails_bootstrap_form/components/errors.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# -*- encoding: utf-8 -*-
# -*- frozen_string_literal: true -*-
# -*- warn_indent: true -*-

module RailsBootstrapForm
module Components
module Errors
extend ActiveSupport::Concern

def self.included(base_class)
def is_invalid?(attribute)
(attribute && object.respond_to?(:errors) && object.errors[attribute].any?) ||
has_association_error?(attribute)
end

def input_with_error(attribute, &block)
input = capture(&block)
input << generate_error(attribute)
input
end

def generate_error(attribute)
if is_invalid?(attribute)
error_text = error_messages(attribute)
error_klass = "invalid-feedback"

tag.div(error_text, class: error_klass)
end
end

def has_association_error?(attribute)
object.class.reflections.any? do |association_name, association|
next unless is_belongs_to_association?(association)
next unless is_association_same?(attribute, association)

object.errors[association_name].any?
end
end

def error_messages(attribute)
messages = object.errors[attribute]

object.class.reflections.each do |association_name, association|
next unless is_belongs_to_association?(association)
next unless is_association_same?(attribute, association)

messages << object.errors[association_name]
end

messages.flatten.to_sentence
end

def is_belongs_to_association?(association)
association.is_a?(ActiveRecord::Reflection::BelongsToReflection)
end

def is_association_same?(attribute, association)
(association.foreign_key == attribute.to_s)
end

private :is_invalid?, :input_with_error, :generate_error,
:has_association_error?, :error_messages,
:is_belongs_to_association?, :is_association_same?
end
end
end
end
1 change: 1 addition & 0 deletions lib/rails_bootstrap_form/components/labels.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def label_classes(attribute, bootstrap_options)
classes = [bootstrap_options.label_class, bootstrap_options.additional_label_class]
classes << bootstrap_options.hide_class if bootstrap_options.hide_label
classes << "required" if is_attribute_required?(attribute)
classes << "is-invalid" if is_invalid?(attribute)
classes.flatten.compact
end

Expand Down
2 changes: 1 addition & 1 deletion lib/rails_bootstrap_form/components/required_field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def is_field_required?(attribute, options)
end
end

def required_field_options(options, attribute)
def required_field_options(attribute, options)
required = is_field_required?(attribute, options)

{}.tap do |option|
Expand Down
40 changes: 35 additions & 5 deletions lib/rails_bootstrap_form/field_wrapper_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,24 @@ def field_wrapper(attribute, bootstrap_options, options, &block)
label = label(attribute, bootstrap_options)
help_text = help_text(attribute, bootstrap_options)

tag.div(class: field_wrapper_classes) do
concat(label)
concat(capture(&block))
concat(help_text)
if bootstrap_options.floating
tag.div(class: field_wrapper_classes) do
concat(input_group_wrapper(attribute, bootstrap_options) do
tag.div(class: floating_label_classes(attribute)) do
concat(capture(&block))
concat(label)
end
end)
concat(help_text)
end
else
tag.div(class: field_wrapper_classes) do
concat(label)
concat(input_group_wrapper(attribute, bootstrap_options) do
capture(&block)
end)
concat(help_text)
end
end
end

Expand All @@ -42,12 +56,28 @@ def field_css_options(attribute, bootstrap_options, options, html_options)
bootstrap_options.field_class,
bootstrap_options.additional_field_class
]
field_classes << "is-invalid" if is_invalid?(attribute)

css_options[:class] = field_classes.flatten.compact

css_options.merge!(required_field_options(attribute, options))

if bootstrap_options.floating
css_options[:placeholder] ||= label_text(attribute, bootstrap_options)
end

css_options
end

def floating_label_classes(attribute)
classes = Array("form-floating")
# Floating label fields with input group requires `is-invalid` class in
# order to display error messages.
classes << "is-invalid" if is_invalid?(attribute)
classes
end

private :field_wrapper, :field_wrapper_classes, :form_wrapper_default_class,
:field_css_options
:field_css_options, :floating_label_classes
end
end
49 changes: 49 additions & 0 deletions lib/rails_bootstrap_form/input_group_builder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# -*- encoding: utf-8 -*-
# -*- frozen_string_literal: true -*-
# -*- warn_indent: true -*-

module RailsBootstrapForm
module InputGroupBuilder
extend ActiveSupport::Concern

def self.included(base_class)
def input_group_wrapper(attribute, bootstrap_options, &block)
input = capture(&block) || ActiveSupport::SafeBuffer.new

prepend = attach_input(bootstrap_options, :prepend)
append = attach_input(bootstrap_options, :append)

input = prepend + input + append
input += generate_error(attribute)

input = tag.div(input, class: input_group_classes(attribute, bootstrap_options))

input
end

def input_group_classes(attribute, bootstrap_options)
classes = ["input-group", bootstrap_options.additional_input_group_class]
# Require `has-validation` class if field has errors.
classes << "has-validation" if is_invalid?(attribute)
classes.flatten.compact
end

def attach_input(bootstrap_options, key)
tags = [*bootstrap_options.send(key)].map do |item|
input_group_content(item)
end

ActiveSupport::SafeBuffer.new(tags.join)
end

def input_group_content(content)
return content if /button|submit/.match?(content)

tag.span(content.html_safe, class: "input-group-text")
end

private :input_group_wrapper, :input_group_classes, :attach_input,
:input_group_content
end
end
end
2 changes: 1 addition & 1 deletion lib/rails_bootstrap_form/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
# -*- warn_indent: true -*-

module RailsBootstrapForm
VERSION = "0.2.3".freeze
VERSION = "0.3.0".freeze
REQUIRED_RAILS_VERSION = "~> 7.0".freeze
end
2 changes: 1 addition & 1 deletion spec/rails_bootstrap_form_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

RSpec.describe RailsBootstrapForm do
it "has a valid version number" do
expect(RailsBootstrapForm::VERSION).to eq("0.2.3")
expect(RailsBootstrapForm::VERSION).to eq("0.3.0")
end

it "has a valid rails version number" do
Expand Down

0 comments on commit a1fc596

Please sign in to comment.