bootstrap5_helper 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,69 @@
1
+ module Bootstrap5Helper
2
+ # The Alert helper is meant to help you rapidly build Bootstrap Alert
3
+ # components quickly and easily. The dissmiss button is optional.
4
+ #
5
+ class Alert < Component
6
+ # Class constructor
7
+ #
8
+ # @param [Class] template - Template in which your are binding too.
9
+ # @param [NilClass|String|Symbol|Hash] context_or_options
10
+ # @param [Hash] opts
11
+ # @option opts [String] :id
12
+ # @option opts [String] :class
13
+ # @option opts [Boolean] :dismissible
14
+ # @return [Alert]
15
+ #
16
+ def initialize(template, context_or_options = nil, opts = {}, &block)
17
+ super(template)
18
+ @context, args = parse_context_or_options(context_or_options, opts)
19
+
20
+ @id = args.fetch(:id, uuid)
21
+ @class = args.fetch(:class, '')
22
+ @dismissible = args.fetch(:dismissible, false)
23
+ @content = block || proc { '' }
24
+ end
25
+
26
+ # The dissmiss button, if the element has one.
27
+ #
28
+ # @return [String]
29
+ #
30
+ def close_button
31
+ content_tag(
32
+ :button,
33
+ '',
34
+ class: 'btn-close',
35
+ data: { 'bs-dismiss' => 'alert' },
36
+ aria: { label: 'Close' }
37
+ )
38
+ end
39
+
40
+ # Used to render out the Alert component.
41
+ #
42
+ # @return [String]
43
+ #
44
+ def to_s
45
+ content_tag :div, id: @id, class: container_class do
46
+ concat(@dismissible ? close_button : '')
47
+ @content.call(self)
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ # Used to get the container classes.
54
+ #
55
+ # @return [String]
56
+ #
57
+ def container_class
58
+ "alert alert-#{@context} #{@class} #{dismissible_class}"
59
+ end
60
+
61
+ # Class used on parent element to signify a dismissible button.
62
+ #
63
+ # @return [String]
64
+ #
65
+ def dismissible_class
66
+ @dismissible ? 'alert-dismissible fade show' : ''
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,53 @@
1
+ module Bootstrap5Helper
2
+ # Creates Bootstrap badge components that can be used anywhere.
3
+ #
4
+ #
5
+ class Badge < Component
6
+ # Class constructor
7
+ #
8
+ # @param [ActionView] template
9
+ # @param [NilClass|String|Symbol|Hash] context_or_options
10
+ # @param [Hash] opts
11
+ # @option opts [String] :id
12
+ # @option opts [String] :class
13
+ # @option opts [Hash] : :data
14
+ #
15
+ def initialize(template, context_or_options = nil, opts = {}, &block)
16
+ super(template)
17
+ @context, args = parse_context_or_options(context_or_options, opts)
18
+
19
+ @id = args.fetch(:id, nil)
20
+ @class = args.fetch(:class, '')
21
+ @data = args.fetch(:data, {})
22
+ @content = block || proc { '' }
23
+ end
24
+
25
+ # String representation of the object.
26
+ #
27
+ # @return [String]
28
+ #
29
+ def to_s
30
+ content_tag(
31
+ config(:badges, :span),
32
+ id: @id,
33
+ class: container_class,
34
+ data: @data
35
+ ) do
36
+ @content.call(self)
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ # Used to get the container classes.
43
+ #
44
+ # @return [String]
45
+ #
46
+ def container_class
47
+ string = 'badge '
48
+ string += @context == 'secondary' ? 'bg-secondary' : "bg-#{@context}"
49
+ string += " #{@class}"
50
+ string
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,58 @@
1
+ module Bootstrap5Helper
2
+ # Builds a Toast component.
3
+ #
4
+ #
5
+ class Callout < Component
6
+ # @param [ActionView] template - Template in which your are binding too.
7
+ # @param [NilClass|String|Symbol|Hash] context_or_options - Bootstrap class context, or options hash.
8
+ # @param [Hash] opts
9
+ # @option opts [String] :id
10
+ # @option opts [String] :class
11
+ # @option opts [Hash] :data
12
+ # @return [Callout]
13
+ #
14
+ def initialize(template, context_or_options = nil, opts = {}, &block)
15
+ super(template)
16
+ @context, args = parse_context_or_options(context_or_options, opts)
17
+
18
+ @id = args.fetch(:id, nil)
19
+ @class = args.fetch(:class, '')
20
+ @data = args.fetch(:data, {})
21
+ @content = block || proc { '' }
22
+ end
23
+
24
+ # Creates the header component for the Callout.
25
+ #
26
+ # @param [String|Hash] text_or_options
27
+ # @param [Hash] opts
28
+ # @option opts [String] :id
29
+ # @option opts [String] :class
30
+ # @option opts [Hash] :data
31
+ # @return [String]
32
+ #
33
+ def header(text_or_options = nil, opts = {}, &block)
34
+ text = text_or_options.is_a?(String) ? text_or_options : nil
35
+ content_tag(config({ callouts: :header }, :h4), text, opts, &block)
36
+ end
37
+
38
+ # Returns a string representation of the component.
39
+ #
40
+ # @return [String]
41
+ #
42
+ def to_s
43
+ content_tag :div, id: @id, class: container_class, data: @data do
44
+ @content.call(self)
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ # Used to get the container classes.
51
+ #
52
+ # @return [String]
53
+ #
54
+ def container_class
55
+ "callout callout-#{@context} #{@class}"
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,204 @@
1
+ module Bootstrap5Helper
2
+ # Used to build Bootstrap Card components. Cards are wildly used through Bootstrap 4.
3
+ #
4
+ #
5
+ class Card < Component
6
+ # Used to initialize a new Card component.
7
+ #
8
+ # @param [ActionView] template
9
+ # @param [Hash] opts
10
+ # @option opts [String] :id
11
+ # @option opts [String] :class
12
+ # @option opts [Hash] :data
13
+ # @return [Card]
14
+ #
15
+ def initialize(template, opts = {}, &block)
16
+ super(template)
17
+
18
+ @id = opts.fetch(:id, '')
19
+ @class = opts.fetch(:class, '')
20
+ @data = opts.fetch(:data, nil)
21
+ @content = block || proc { '' }
22
+ end
23
+
24
+ # Builds the Header component.
25
+ #
26
+ # @param [Symbol|Hash|NilClass] tag_or_options
27
+ # @param [Hash] opts
28
+ # @option opts [String] :id
29
+ # @option opts [String] :class
30
+ # @option opts [Hash] :data
31
+ # @return [String]
32
+ #
33
+ def header(tag_or_options = nil, opts = {}, &block)
34
+ tag, args = parse_tag_or_options(tag_or_options, opts)
35
+ build_base_component(
36
+ tag || config({ cards: :header }, :h5),
37
+ :header,
38
+ args,
39
+ &block
40
+ )
41
+ end
42
+
43
+ # Builds the Body component.
44
+ #
45
+ # @param [Symbol|Hash|NilClass] tag_or_options
46
+ # @param [Hash] opts
47
+ # @option opts [String] :id
48
+ # @option opts [String] :class
49
+ # @option opts [Hash] :data
50
+ # @return [String]
51
+ #
52
+ def body(tag_or_options = nil, opts = {}, &block)
53
+ tag, args = parse_tag_or_options(tag_or_options, opts)
54
+ build_base_component(
55
+ tag || config({ cards: :body }, :div),
56
+ :body,
57
+ args,
58
+ &block
59
+ )
60
+ end
61
+
62
+ # Builds the Footer component.
63
+ #
64
+ # @param [Symbol|Hash|NilClass] tag_or_options
65
+ # @param [Hash] opts
66
+ # @option opts [String] :id
67
+ # @option opts [String] :class
68
+ # @option opts [Hash] :data
69
+ # @return [String]
70
+ #
71
+ def footer(tag_or_options = nil, opts = {}, &block)
72
+ tag, args = parse_tag_or_options(tag_or_options, opts)
73
+ build_base_component(
74
+ tag || config({ cards: :footer }, :div),
75
+ :footer,
76
+ args,
77
+ &block
78
+ )
79
+ end
80
+
81
+ # Builds a Title component.
82
+ #
83
+ # @param [Symbol|Hash|NilClass] tag_or_options
84
+ # @param [Hash] opts
85
+ # @option opts [String] :id
86
+ # @option opts [String] :class
87
+ # @option opts [Hash] :data
88
+ # @return [String]
89
+ #
90
+ def title(tag_or_options = nil, opts = {}, &block)
91
+ tag, args = parse_tag_or_options(tag_or_options, opts)
92
+ build_sub_component(
93
+ tag || config({ cards: :title }, :h5),
94
+ :title,
95
+ args,
96
+ &block
97
+ )
98
+ end
99
+
100
+ # Builds a Text component.
101
+ #
102
+ # @param [Symbol|Hash|NilClass] tag_or_options
103
+ # @param [Hash] opts
104
+ # @option opts [String] :id
105
+ # @option opts [String] :class
106
+ # @option opts [Hash] :data
107
+ # @return [String]
108
+ #
109
+ def text(tag_or_options = nil, opts = {}, &block)
110
+ tag, args = parse_tag_or_options(tag_or_options, opts)
111
+ build_sub_component(
112
+ tag || config(:card_text, :p),
113
+ :text,
114
+ args,
115
+ &block
116
+ )
117
+ end
118
+
119
+ # Simple image element for cards.
120
+ #
121
+ # @param [String] src
122
+ # @param [Hash] opts
123
+ # @option opts [String] :id
124
+ # @option opts [String] :class
125
+ # @option opts [Hash] :data
126
+ # @option opts [Hash] :aria
127
+ # @return [String]
128
+ #
129
+ def image(src, opts = {})
130
+ (opts[:class] ||= '') << 'card-img'
131
+ @template.image_tag(src, opts)
132
+ end
133
+
134
+ # Builds an Image Cap component.
135
+ #
136
+ # @param [String] src,
137
+ # @param [Symbol|String] type
138
+ # @param [Hash] opts
139
+ # @return [String]
140
+ #
141
+ def image_cap(src, type = :top, opts = {})
142
+ (opts[:class] ||= '') << "card-img-#{type}"
143
+ @template.image_tag(src, opts)
144
+ end
145
+
146
+ # Builds a Img Overlay component.
147
+ #
148
+ # @param [Hash] args
149
+ # @option args [String] :id
150
+ # @option args [String] :class
151
+ # @option args [Hash] :data
152
+ # @return [String]
153
+ #
154
+ def image_overlay(args = {}, &block)
155
+ build_base_component(:div, 'img-overlay', args, &block)
156
+ end
157
+
158
+ # Outputs the Object in its String representation.
159
+ #
160
+ # @return [String]
161
+ #
162
+ def to_s
163
+ content_tag :div, id: @id, class: "card #{@class}", data: @data do
164
+ @content.call(self)
165
+ end
166
+ end
167
+
168
+ private
169
+
170
+ # Used to build basic DIV components.
171
+ #
172
+ # @param [String] type
173
+ # @param [Mixed] args
174
+ # @return [String]
175
+ #
176
+ def build_base_component(tag, type, args, &block)
177
+ build_sub_component(tag, type, args, &block)
178
+ end
179
+
180
+ # Used to build various DOM components.
181
+ #
182
+ # @param [Symbol] tag
183
+ # @param [String] type
184
+ # @param [Hash] args
185
+ # @option args [String] :id
186
+ # @option args [String] :class
187
+ # @option args [Hash] :data
188
+ # @return [String]
189
+ #
190
+ def build_sub_component(tag, type, args, &block)
191
+ id = args.fetch(:id, '')
192
+ klass = args.fetch(:class, '')
193
+ data = args.fetch(:data, {})
194
+
195
+ content_tag(
196
+ tag,
197
+ id: id,
198
+ class: "card-#{type} #{klass}",
199
+ data: data,
200
+ &block
201
+ )
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,156 @@
1
+ module Bootstrap5Helper
2
+ # This super class is meant to contain commonly used methods that
3
+ # all sub classes can leverage.
4
+ #
5
+ # @note Every component that inherits from this class, needs to call the parent
6
+ # initialization method! In order to properly render erb blocks within the
7
+ # proper context, we need the template. The only way to get this, is to pass
8
+ # in the template.
9
+ #
10
+ # @note the `context` mentioned above, refers to the context of `@template` and
11
+ # not to be confused with `@context` that can be found in the sub classes.
12
+ # `@context` refers to the Bootstrap class context of the component.
13
+ #
14
+ class Component
15
+ # Used to ensure that the helpers always have the propert context for
16
+ # rendering and bindings.
17
+ #
18
+ # @param [Class] template
19
+ #
20
+ def initialize(template)
21
+ @template = template
22
+ end
23
+
24
+ # rubocop:disable Style/OptionalBooleanParameter
25
+
26
+ # Used to pass all context of content_tag to the template. This ensures
27
+ # proper template binding of variables and methods!
28
+ #
29
+ # @param [String] name
30
+ # @param [Hash|NilClass] content_or_options_with_block
31
+ # @param [Hash|NilClass] options
32
+ # @param [Boolean] escape
33
+ # @return [String]
34
+ #
35
+ def content_tag(
36
+ name,
37
+ content_or_options_with_block = nil,
38
+ options = nil,
39
+ escape = true,
40
+ &block
41
+ )
42
+ @template.content_tag(
43
+ name,
44
+ content_or_options_with_block,
45
+ options,
46
+ escape,
47
+ &block
48
+ )
49
+ end
50
+ # rubocop:enable Style/OptionalBooleanParameter
51
+
52
+ # Used to pass all context of the capture tag to then template. This ensures
53
+ # proper template binding of variables and methods!
54
+ #
55
+ # @param [Mixed] args
56
+ # @return [String]
57
+ #
58
+ def capture(*args)
59
+ @template.capture(*args)
60
+ end
61
+
62
+ # Used to pass all concat references to the template. This ensures proper
63
+ # binding. Concat adds a String to the template Output buffer. Useful when
64
+ # trying to add a String with no block.
65
+ #
66
+ # @param [String] text
67
+ # @return [String]
68
+ #
69
+ def concat(text)
70
+ @template.concat(text)
71
+ end
72
+
73
+ # Used to parse method arguments. If the first argument is
74
+ # a Hash, then it is assumed that the user left off the bootstrap
75
+ # contectual class. So we will assign it to `secondary` and
76
+ # return the Hash to be used as options.
77
+ #
78
+ # @param [Hash|NilClass|String|Symbol] args
79
+ # @return [Array]
80
+ #
81
+ def parse_context_or_options(*args)
82
+ parse_arguments(*args, 'secondary')
83
+ end
84
+
85
+ # Used to parse method arguments. If the first argument is
86
+ # a Hash, then it is assumed that the user left off the tag
87
+ # element. So we will assign it to <tt>NilClass</tt> and
88
+ # return the Hash to be used as options.
89
+ #
90
+ # @param [Hash|NilClass|String|Symbol] args
91
+ # @return [Array]
92
+ #
93
+ def parse_tag_or_options(*args)
94
+ parse_arguments(*args, nil)
95
+ end
96
+
97
+ # Used to parse method arguments. If the first argument is
98
+ # a Hash, then it is assumed that the user left out the text
99
+ # string. So we will assign it to <tt>NilClass</tt> and
100
+ # return the Hash to be used as options.
101
+ #
102
+ # @param [Hash|NilClass|String|Symbol] args
103
+ # @return [Array]
104
+ #
105
+ def parse_text_or_options(*args)
106
+ parse_arguments(*args, nil)
107
+ end
108
+
109
+ # Used to parse method arguments. If the first argument is
110
+ # a Hash, then it is assumed that the user skipped the default
111
+ # argument. So we will assign it to `default` provided and
112
+ # return the Hash to be used as options.
113
+ #
114
+ # @param [Hash|NilClass|String|Symbol] args
115
+ # @return [Array]
116
+ #
117
+ def parse_arguments(*args, default)
118
+ first, second = *args
119
+ case first
120
+ when Hash, NilClass
121
+ [default, first || second]
122
+ when Symbol, String
123
+ [first, second]
124
+ end
125
+ end
126
+
127
+ # Used to generate a (hopefully) unique ID for DOM elements. Used as a
128
+ # fallback if the user doesn't specify one.
129
+ #
130
+ # @return [String]
131
+ #
132
+ def uuid
133
+ (0...10).map { rand(65..90).chr }.join
134
+ end
135
+
136
+ # Used to get config settings inside of components quicker.
137
+ #
138
+ # @param [Symbol|String|Hash] setting
139
+ # @return [Mixed]
140
+ #
141
+ def config(setting, fallback)
142
+ object = Bootstrap5Helper.config
143
+
144
+ value = (
145
+ case setting
146
+ when Hash
147
+ object.send(setting.keys[0])[setting.values[0]] if object.send(setting.keys[0])
148
+ when Symbol, String
149
+ object.send(setting) if object.respond_to?(setting)
150
+ end
151
+ )
152
+
153
+ value || fallback
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,65 @@
1
+ module Bootstrap5Helper
2
+ # Simple configuration object for setting options for the gem.
3
+ #
4
+ # @todo Build a better, more comprehensive system.
5
+ #
6
+ class Configuration
7
+ DEFAULT_SETTINGS = {
8
+ autoload_in_views: true,
9
+ accordions: {
10
+ header: :h2,
11
+ body: :div
12
+ },
13
+ badges: :span,
14
+ callouts: {
15
+ header: :h4
16
+ },
17
+ cards: {
18
+ header: :h5,
19
+ body: :div,
20
+ footer: :div,
21
+ title: :h5,
22
+ text: :p
23
+ },
24
+ dropdowns: {},
25
+ dropdown_menus: {
26
+ text: :span,
27
+ header: :h6,
28
+ divider: :div
29
+ },
30
+ modals: {
31
+ title: :h5
32
+ },
33
+ navs: {
34
+ base: :ul
35
+ },
36
+ offcanvas: {
37
+ header: :div,
38
+ title: :h5,
39
+ close: :button,
40
+ body: :div,
41
+ trigger: :div
42
+ },
43
+ page_header: :h1
44
+ }.freeze
45
+
46
+ attr_accessor(*DEFAULT_SETTINGS.keys)
47
+
48
+ # Class constructor
49
+ #
50
+ # @param [Hash] _args
51
+ # @return [ClassName]
52
+ #
53
+ def initialize(_args = {})
54
+ DEFAULT_SETTINGS.each { |key, value| instance_variable_set("@#{key}", value) }
55
+ end
56
+
57
+ # Simple predicate method
58
+ #
59
+ # @return [Boolean]
60
+ #
61
+ def autoload_in_views?
62
+ @autoload_in_views
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,28 @@
1
+ module Bootstrap5Helper
2
+ # Simple class for storing constants
3
+ #
4
+ #
5
+ class Constants
6
+ COMPONENTS = %i[
7
+ component
8
+ alert
9
+ accordion
10
+ accordion/item
11
+ badge
12
+ card
13
+ callout
14
+ configuration
15
+ dropdown
16
+ dropdown/menu
17
+ input_group
18
+ modal
19
+ nav
20
+ offcanvas
21
+ offcanvas/content
22
+ page_header
23
+ spinner
24
+ tab
25
+ tab/content
26
+ ].freeze
27
+ end
28
+ end