bootstrap5_helper 1.0.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.
@@ -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