bootstrap5_helper 1.2.1 → 2.0.0.beta

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: 8a6aaec7186d656a26d239a28ddd64ac135a0e734a8f1d90c546186a78cfe967
4
- data.tar.gz: dc3fb21a0eaced7579b8dc6b6946b6fc1eadb3354581449e521ea49cde32c778
3
+ metadata.gz: b80e1976cb72cb25fc00dd66922607696c0ecd768f5a13a4fe4133a0b86c8df0
4
+ data.tar.gz: 490c5c5908ae56ca91ea9be973a52c3a9fc10d9e98f18b80518663816c939259
5
5
  SHA512:
6
- metadata.gz: ccc3bd5934a64d589dbefedb634ee3acd27cef1841992663abfa6233fee8bd0824ae2200b690fa2e6f2a70e0ce1cbd5876e9634f4e81ba0821b94a6105917e2e
7
- data.tar.gz: c204cc8a8d958f8ce9881e2ba4433a20fa59ec7231d142d578fb2c4c974eb4572320f9f397c4d93688b9d27855b7bbf3677826dab7cc7d2b899acf7379bdec78
6
+ metadata.gz: 8aa38ac1d5a6577d1f675ad65fee42aa6bd3b4bb9a48193b866ebfab2663de1955e2a5c81cfb3fba19ee51f977bb9bc4e62bad8395b74f3e51f7fec939a1cc2f
7
+ data.tar.gz: f10d1aedb9e4b448a1d0c11ac157d00733dc46a9f64427a0bfc3d457465ccc12c6a4f9e56892d90811c28a09b994f90a0e0aa6099b442631da21f340f39aeb7e
@@ -17,14 +17,15 @@ module Bootstrap5Helper
17
17
  super(template)
18
18
 
19
19
  @parent = parent_id
20
- @id = opts.fetch(:id, uuid)
21
- @class = opts.fetch(:class, '')
22
- @data = opts.fetch(:data, {})
23
- @expanded = opts.fetch(:expanded, false)
24
- @collapse = opts.fetch(:collapse, {})
25
- @collapse_id = @collapse.fetch(:id, uuid)
26
- @collapse_klass = @collapse.fetch(:class, '')
27
- @collapse_data = @collapse.fetch(:data, {})
20
+ @attrs = opts
21
+ @id = @attrs.delete(:id) { uuid }
22
+ @class = @attrs.delete(:class) { '' }
23
+ @data = @attrs.delete(:data) { {} }
24
+ @expanded = @attrs.delete(:expanded) { false }
25
+ @collapse = @attrs.delete(:collapse) { {} }
26
+ @collapse_id = @collapse.delete(:id) { uuid }
27
+ @collapse_klass = @collapse.delete(:class) { '' }
28
+ @collapse_data = @collapse.delete(:data) { {} }
28
29
  @header_id = uuid
29
30
  @content = block || proc { '' }
30
31
  end
@@ -51,15 +52,17 @@ module Bootstrap5Helper
51
52
  def header(*tag_or_options, &block)
52
53
  tag, args = parse_tag_or_options(*tag_or_options, {})
53
54
 
54
- @header_id = args.fetch(:id, @header_id)
55
- klass = args.fetch(:class, '')
56
- data = args.fetch(:data, {})
55
+ @header_id = args.delete(:id) { @header_id }
56
+ klass = args.delete(:class) { '' }
57
+ data = args.delete(:data) { {} }
57
58
 
58
59
  content_tag(
59
60
  tag || config({ accordions: :header }, :h2),
60
- id: @header_id,
61
- class: "accordion-header #{klass}",
62
- data: data
61
+ {
62
+ id: @header_id,
63
+ class: "accordion-header #{klass}",
64
+ data: data
65
+ }.merge(args)
63
66
  ) do
64
67
  content_tag(
65
68
  :button,
@@ -90,9 +93,9 @@ module Bootstrap5Helper
90
93
  # @return [String]
91
94
  #
92
95
  def body(opts = {}, &block)
93
- id = opts.fetch(:id, uuid)
94
- klass = opts.fetch(:class, '')
95
- data = opts.fetch(:data, {})
96
+ id = opts.delete(:id) { uuid }
97
+ klass = opts.delete(:class) { '' }
98
+ data = opts.delete(:data) { {} }
96
99
 
97
100
  content_tag(
98
101
  :div,
@@ -105,9 +108,11 @@ module Bootstrap5Helper
105
108
  ) do
106
109
  content_tag(
107
110
  :div,
108
- id: id,
109
- class: "accordion-body #{klass}",
110
- data: data,
111
+ {
112
+ id: id,
113
+ class: "accordion-body #{klass}",
114
+ data: data
115
+ }.merge(opts),
111
116
  &block
112
117
  )
113
118
  end
@@ -119,7 +124,14 @@ module Bootstrap5Helper
119
124
  # @return [String]
120
125
  #
121
126
  def to_s
122
- content_tag :div, id: @id, class: "accordion-item #{@class}", data: @data do
127
+ content_tag(
128
+ :div,
129
+ {
130
+ id: @id,
131
+ class: "accordion-item #{@class}",
132
+ data: @data
133
+ }.merge(@attrs)
134
+ ) do
123
135
  @content.call(self)
124
136
  end
125
137
  end
@@ -16,11 +16,12 @@ module Bootstrap5Helper
16
16
  def initialize(template, opts = {}, &block)
17
17
  super(template)
18
18
 
19
- @id = opts.fetch(:id, uuid)
20
- @class = opts.fetch(:class, '')
21
- @data = opts.fetch(:data, {})
22
- @always_open = opts.fetch(:always_open, false)
23
- @flush = opts.fetch(:flush, false)
19
+ @attrs = opts
20
+ @id = @attrs.delete(:id) { uuid }
21
+ @class = @attrs.delete(:class) { '' }
22
+ @data = @attrs.delete(:data) { {} }
23
+ @always_open = @attrs.delete(:always_open) { false }
24
+ @flush = @attrs.delete(:flush) { false }
24
25
  @content = block || proc { '' }
25
26
  end
26
27
 
@@ -39,9 +40,11 @@ module Bootstrap5Helper
39
40
  def to_s
40
41
  content_tag(
41
42
  :div,
42
- id: @id,
43
- class: "accordion #{@flush ? 'accordion-flush' : ''} #{@class}",
44
- data: @data
43
+ {
44
+ id: @id,
45
+ class: "accordion #{@flush ? 'accordion-flush' : ''} #{@class}",
46
+ data: @data
47
+ }.merge(@attrs)
45
48
  ) do
46
49
  @content.call(self)
47
50
  end
@@ -17,10 +17,11 @@ module Bootstrap5Helper
17
17
  super(template)
18
18
  @context, args = parse_context_or_options(context_or_options, opts)
19
19
 
20
- @id = args.fetch(:id, uuid)
21
- @class = args.fetch(:class, '')
22
- @data = args.fetch(:data, {})
23
- @dismissible = args.fetch(:dismissible, false)
20
+ @attrs = args
21
+ @id = @attrs.delete(:id) { uuid }
22
+ @class = @attrs.delete(:class) { '' }
23
+ @data = @attrs.delete(:data) { {} }
24
+ @dismissible = @attrs.delete(:dismissible) { false }
24
25
  @content = block || proc { '' }
25
26
  end
26
27
 
@@ -43,7 +44,14 @@ module Bootstrap5Helper
43
44
  # @return [String]
44
45
  #
45
46
  def to_s
46
- content_tag(:div, id: @id, class: container_class, data: @data) do
47
+ content_tag(
48
+ :div,
49
+ {
50
+ id: @id,
51
+ class: container_class,
52
+ data: @data
53
+ }.merge(@attrs)
54
+ ) do
47
55
  concat(@dismissible ? close_button : '')
48
56
  @content.call(self)
49
57
  end
@@ -16,9 +16,10 @@ module Bootstrap5Helper
16
16
  super(template)
17
17
  @context, args = parse_context_or_options(context_or_options, opts)
18
18
 
19
- @id = args.fetch(:id, nil)
20
- @class = args.fetch(:class, '')
21
- @data = args.fetch(:data, {})
19
+ @attrs = args
20
+ @id = @attrs.delete(:id) { nil }
21
+ @class = @attrs.delete(:class) { '' }
22
+ @data = @attrs.delete(:data) { {} }
22
23
  @content = block || proc { '' }
23
24
  end
24
25
 
@@ -29,9 +30,11 @@ module Bootstrap5Helper
29
30
  def to_s
30
31
  content_tag(
31
32
  config({ badges: :base }, :span),
32
- id: @id,
33
- class: container_class,
34
- data: @data
33
+ {
34
+ id: @id,
35
+ class: container_class,
36
+ data: @data
37
+ }.merge(@attrs)
35
38
  ) do
36
39
  @content.call(self)
37
40
  end
@@ -15,9 +15,10 @@ module Bootstrap5Helper
15
15
  super(template)
16
16
  @context, args = parse_context_or_options(context_or_options, opts)
17
17
 
18
- @id = args.fetch(:id, nil)
19
- @class = args.fetch(:class, '')
20
- @data = args.fetch(:data, {})
18
+ @attrs = args
19
+ @id = @attrs.delete(:id) { nil }
20
+ @class = @attrs.delete(:class) { '' }
21
+ @data = @attrs.delete(:data) { {} }
21
22
  @content = block || proc { '' }
22
23
  end
23
24
 
@@ -40,7 +41,14 @@ module Bootstrap5Helper
40
41
  # @return [String]
41
42
  #
42
43
  def to_s
43
- content_tag :div, id: @id, class: container_class, data: @data do
44
+ content_tag(
45
+ :div,
46
+ {
47
+ id: @id,
48
+ class: container_class,
49
+ data: @data
50
+ }.merge(@attrs)
51
+ ) do
44
52
  @content.call(self)
45
53
  end
46
54
  end
@@ -1,7 +1,7 @@
1
1
  module Bootstrap5Helper
2
- # Used to build Bootstrap Card components. Cards are wildly used through Bootstrap 4.
3
- #
4
- #
2
+ # rubocop:disable Metrics/ClassLength
3
+
4
+ # Used to build Bootstrap Card components..
5
5
  class Card < Component
6
6
  # Used to initialize a new Card component.
7
7
  #
@@ -15,9 +15,10 @@ module Bootstrap5Helper
15
15
  def initialize(template, opts = {}, &block)
16
16
  super(template)
17
17
 
18
- @id = opts.fetch(:id, '')
19
- @class = opts.fetch(:class, '')
20
- @data = opts.fetch(:data, nil)
18
+ @attrs = opts
19
+ @id = @attrs.delete(:id) { '' }
20
+ @class = @attrs.delete(:class) { '' }
21
+ @data = @attrs.delete(:data) { {} }
21
22
  @content = block || proc { '' }
22
23
  end
23
24
 
@@ -228,7 +229,14 @@ module Bootstrap5Helper
228
229
  # @return [String]
229
230
  #
230
231
  def to_s
231
- content_tag :div, id: @id, class: "card #{@class}", data: @data do
232
+ content_tag(
233
+ :div,
234
+ {
235
+ id: @id,
236
+ class: "card #{@class}",
237
+ data: @data
238
+ }.merge(@attrs)
239
+ ) do
232
240
  @content.call(self)
233
241
  end
234
242
  end
@@ -256,17 +264,21 @@ module Bootstrap5Helper
256
264
  # @return [String]
257
265
  #
258
266
  def build_sub_component(tag, type, args, &block)
259
- id = args.fetch(:id, '')
260
- klass = args.fetch(:class, '')
261
- data = args.fetch(:data, {})
267
+ attrs = args
268
+ id = attrs.delete(:id) { '' }
269
+ klass = attrs.delete(:class) { '' }
270
+ data = attrs.delete(:data) { {} }
262
271
 
263
272
  content_tag(
264
273
  tag,
265
- id: id,
266
- class: "card-#{type} #{klass}",
267
- data: data,
274
+ {
275
+ id: id,
276
+ class: "card-#{type} #{klass}",
277
+ data: data
278
+ }.merge(attrs),
268
279
  &block
269
280
  )
270
281
  end
271
282
  end
283
+ # rubocop:enable Metrics/ClassLength
272
284
  end
@@ -20,9 +20,11 @@ module Bootstrap5Helper
20
20
  def initialize(template, *context_or_options, &block)
21
21
  super(template)
22
22
  @context, args = parse_context_or_options(*context_or_options, {})
23
- @id = args.fetch(:id, '')
24
- @class = args.fetch(:class, '')
25
- @data = args.fetch(:data, nil)
23
+
24
+ @attrs = args
25
+ @id = @attrs.delete(:id) { '' }
26
+ @class = @attrs.delete(:class) { '' }
27
+ @data = @attrs.delete(:data) { {} }
26
28
  @content = block || proc { '' }
27
29
  end
28
30
 
@@ -47,13 +49,14 @@ module Bootstrap5Helper
47
49
  # @return [Nav]
48
50
  #
49
51
  def nav(*tag_or_options, &block)
50
- tag, args = parse_tag_or_options(*tag_or_options, {})
51
- args[:class] = (args[:class] || '') << ' nav-tabs card-header-tabs'
52
- args[:data] = (args[:data] || {}).merge('bs-toggle' => 'tab')
53
- args[:child] = (args[:child] || {}).merge(
54
- data: {
55
- 'bs-toggle' => 'tab',
56
- 'bs-display' => 'static'
52
+ tag, args = parse_tag_or_options(*tag_or_options, {})
53
+ args[:class] = (args[:class] || '') << ' nav-tabs card-header-tabs'
54
+ args[:bs_attrs] = (args[:bs_attrs] || {}).merge(
55
+ {
56
+ data: {
57
+ 'bs-toggle' => 'tab',
58
+ 'bs-display' => 'static'
59
+ }
57
60
  }
58
61
  )
59
62
 
@@ -82,9 +85,11 @@ module Bootstrap5Helper
82
85
  def to_s
83
86
  content_tag(
84
87
  :div,
85
- class: "card with-nav-tabs-#{@context} #{@class}",
86
- id: @id,
87
- data: @data
88
+ {
89
+ class: "card with-nav-tabs-#{@context} #{@class}",
90
+ id: @id,
91
+ data: @data
92
+ }.merge(@attrs)
88
93
  ) do
89
94
  @content.call(self)
90
95
  end
@@ -18,9 +18,10 @@ module Bootstrap5Helper
18
18
 
19
19
  @context, args = parse_context_or_options(context_or_options, opts)
20
20
 
21
- @id = args.fetch(:id, nil)
22
- @class = args.fetch(:class, '')
23
- @data = args.fetch(:data, {})
21
+ @attrs = args
22
+ @id = @attrs.delete(:id) { nil }
23
+ @class = @attrs.delete(:class) { '' }
24
+ @data = @attrs.delete(:data) { {} }
24
25
  @content = block || proc { '' }
25
26
  end
26
27
 
@@ -42,9 +43,11 @@ module Bootstrap5Helper
42
43
  def to_s
43
44
  content_tag(
44
45
  :div,
45
- id: @id,
46
- class: "input-group #{size_class} #{@class}",
47
- data: @data
46
+ {
47
+ id: @id,
48
+ class: "input-group #{size_class} #{@class}",
49
+ data: @data
50
+ }.merge(@attrs)
48
51
  ) do
49
52
  @content.call(self)
50
53
  end
@@ -21,14 +21,15 @@ module Bootstrap5Helper
21
21
  def initialize(template, opts = {}, &block)
22
22
  super(template)
23
23
 
24
- @id = opts.fetch(:id, uuid)
25
- @class = opts.fetch(:class, '')
26
- @data = opts.fetch(:data, {})
27
- @scrollable = opts.fetch(:scrollable, false)
28
- @vcentered = opts.fetch(:vcentered, false)
29
- @static = opts.fetch(:static, false)
30
- @fullscreen = opts.fetch(:fullscreen, false)
31
- @size = opts.fetch(:size, nil)
24
+ @attrs = opts
25
+ @id = @attrs.delete(:id) { uuid }
26
+ @class = @attrs.delete(:class) { '' }
27
+ @data = @attrs.delete(:data) { {} }
28
+ @scrollable = @attrs.delete(:scrollable) { false }
29
+ @vcentered = @attrs.delete(:vcentered) { false }
30
+ @static = @attrs.delete(:static) { false }
31
+ @fullscreen = @attrs.delete(:fullscreen) { false }
32
+ @size = @attrs.delete(:size) { nil }
32
33
  @content = block || proc { '' }
33
34
  end
34
35
 
@@ -87,14 +88,19 @@ module Bootstrap5Helper
87
88
  # @return [String]
88
89
  #
89
90
  def close_button(opts = {})
90
- klass = opts.fetch(:class, '')
91
+ attrs = opts
92
+ klass = attrs.delete(:class) { '' }
93
+ data = attrs.delete(:data) { {} }
94
+ aria = attrs.delete(:aria) { {} }
91
95
 
92
96
  content_tag(
93
97
  :button,
94
- type: 'button',
95
- class: block_given? ? klass : 'btn-close',
96
- data: { 'bs-dismiss': 'modal' },
97
- aria: { label: 'Close' }
98
+ {
99
+ type: 'button',
100
+ class: block_given? ? klass : 'btn-close',
101
+ data: data.merge('bs-dismiss' => 'modal'),
102
+ aria: aria.merge(label: 'Close')
103
+ }.merge(attrs)
98
104
  ) do
99
105
  block_given? ? yield : xbutton
100
106
  end
@@ -111,11 +117,13 @@ module Bootstrap5Helper
111
117
 
112
118
  content_tag(
113
119
  :div,
114
- id: @id,
115
- class: "modal #{@class}",
116
- tabindex: -1,
117
- role: 'dialog',
118
- data: @data
120
+ {
121
+ id: @id,
122
+ class: "modal #{@class}",
123
+ tabindex: -1,
124
+ role: 'dialog',
125
+ data: @data
126
+ }.merge(@attrs)
119
127
  ) do
120
128
  content_tag(
121
129
  :div,
@@ -151,15 +159,18 @@ module Bootstrap5Helper
151
159
  # @return [String]
152
160
  #
153
161
  def build_sub_component(tag, type, opts = {}, &block)
154
- id = opts.fetch(:id, nil)
155
- klass = opts.fetch(:class, '')
156
- data = opts.fetch(:data, {})
162
+ attrs = opts
163
+ id = attrs.delete(:id) { nil }
164
+ klass = attrs.delete(:class) { '' }
165
+ data = attrs.delete(:data) { {} }
157
166
 
158
167
  content_tag(
159
168
  tag,
160
- id: id,
161
- class: "modal-#{type} #{klass}",
162
- data: data,
169
+ {
170
+ id: id,
171
+ class: "modal-#{type} #{klass}",
172
+ data: data
173
+ }.merge(attrs),
163
174
  &block
164
175
  )
165
176
  end
@@ -1,7 +1,7 @@
1
1
  module Bootstrap5Helper
2
+ # rubocop:disable Metrics/ClassLength
3
+
2
4
  # Builds a Nav Component that can be used in other components.
3
- #
4
- #
5
5
  class Nav < Component
6
6
  # Class constructor
7
7
  #
@@ -11,8 +11,7 @@ module Bootstrap5Helper
11
11
  # @option opts [String] :id
12
12
  # @option opts [String] :class
13
13
  # @option opts [Hash] :data
14
- # @option opts [Array] :dropdown
15
- # @option opts []
14
+ # @option opts [Hash] :bs_attrs
16
15
  #
17
16
  def initialize(template, *tag_or_options, &block)
18
17
  super(template)
@@ -20,17 +19,16 @@ module Bootstrap5Helper
20
19
  @tag, args = parse_tag_or_options(*tag_or_options, {})
21
20
  @tag ||= config({ navs: :base }, :ul)
22
21
 
23
- @id = args.fetch(:id, uuid)
24
- @class = args.fetch(:class, '')
25
- @data = args.fetch(:data, {})
26
- @child = args.fetch(:child, {})
27
- @content = block || proc { '' }
22
+ @attrs = args
23
+ @id = @attrs.delete(:id) { uuid }
24
+ @class = @attrs.delete(:class) { '' }
25
+ @data = @attrs.delete(:data) { {} }
26
+ @bs_attrs = @attrs.delete(:bs_attrs) { {} }
28
27
  @dropdown = Dropdown.new(@template)
28
+ @content = block || proc { '' }
29
29
  end
30
30
 
31
- # rubocop:disable Metrics/MethodLength
32
-
33
- # Adds an nav-item to the nav component. this method gets used when the nav-item
31
+ # Adds an nav-item to the nav component. This method gets used when the nav-item
34
32
  # links to content in a tab or something.
35
33
  #
36
34
  # @param [Symbol|String] target
@@ -39,28 +37,17 @@ module Bootstrap5Helper
39
37
  # @option opts [String] :class
40
38
  # @option opts [Hash] :data
41
39
  # @option opts [Hash] :aria
40
+ # @option opts [Hash] :child
42
41
  # @return [String]
43
42
  #
44
- def item(target, opts = {})
45
- id = opts.fetch(:id, nil)
46
- klass = opts.fetch(:class, '')
47
- data = opts.fetch(:data, {})
48
- aria = opts.fetch(:aria, {})
49
-
50
- nav_item_wrapper id: id, data: data do
51
- content_tag(
52
- :a,
53
- class: "nav-link #{klass}",
54
- href: "##{target}",
55
- tabindex: -1,
56
- data: @child[:data],
57
- aria: aria
58
- ) do
59
- block_given? ? yield : target.to_s.titleize
60
- end
43
+ def item(target, opts = {}, &block)
44
+ case @tag
45
+ when :nav
46
+ nav_item_without_wrapper(target, opts, &block)
47
+ when :ul
48
+ nav_item_with_wrapper(target, opts, &block)
61
49
  end
62
50
  end
63
- # rubocop:enable Metrics/MethodLength
64
51
 
65
52
  # Use this when the nav item is nothing more than a hyperlink.
66
53
  #
@@ -88,6 +75,7 @@ module Bootstrap5Helper
88
75
  # @option opts [String] :class
89
76
  # @option opts [Hash] :data
90
77
  # @option opts [Hash] :aria
78
+ # @option opts [Hash] :child
91
79
  # @return [String]
92
80
  #
93
81
  def dropdown(name, opts = {}, &block)
@@ -96,9 +84,14 @@ module Bootstrap5Helper
96
84
  data = opts.fetch(:data, {}).merge('bs-toggle' => 'dropdown')
97
85
  aria = opts.fetch(:aria, {}).merge(haspopup: true, expanded: false)
98
86
 
99
- data.merge!('bs-display' => 'static') if @child[:data]&.key?('bs-display')
100
-
101
- nav_item_wrapper id: id, class: 'dropdown', data: data do
87
+ nav_item_wrapper(
88
+ id: id,
89
+ class: 'dropdown',
90
+ data: (@bs_attrs[:data] || {}).merge(
91
+ 'bs-toggle' => 'dropdown',
92
+ 'bs-display' => 'static'
93
+ )
94
+ ) do
102
95
  content_tag(
103
96
  :a,
104
97
  name,
@@ -117,34 +110,114 @@ module Bootstrap5Helper
117
110
  # @return [String]
118
111
  #
119
112
  def to_s
120
- content_tag(@tag, id: @id, class: "nav #{@class}", data: @data) do
113
+ content_tag(
114
+ @tag,
115
+ {
116
+ id: @id,
117
+ class: "nav #{@class}",
118
+ data: @data
119
+ }.merge(@attrs)
120
+ ) do
121
121
  @content.call(self)
122
122
  end
123
123
  end
124
124
 
125
125
  private
126
126
 
127
+ # rubocop:disable Metrics/AbcSize
128
+
129
+ # @note This is one of the few places where things deviate
130
+ # a little from the pattern of child elements requiring
131
+ # the :child option class needing to be set in order to
132
+ # pass on the class. The reason being that the default DOM
133
+ # elements built for navs are UL, which means that the
134
+ # majority of them will have children elements. Just wanted
135
+ # an easy process of setting the active nav, without having
136
+ # to remember if you are using :nav or :ul components.
137
+ #
138
+ # @example Nav built with UL(default config) would require the
139
+ # the following for setting the active nav:
140
+ #
141
+ # ```ruby
142
+ # <%= nav_helper do |nav| %>
143
+ # <%= nav.item(child: { class: 'active' }) do
144
+ # <% end %>
145
+ # <% end %>
146
+ #
147
+ # @example With the deviation:
148
+ #
149
+ # <%= nav_helper do |nav| %>
150
+ # <%= nav.item(class: 'active') do
151
+ # <% end %>
152
+ # <% end %>
153
+ # ```
154
+ #
155
+ # @param [Symbol|String] target
156
+ # @param [Hash] opts
157
+ # @option opts [String] :id
158
+ # @option opts [String] :class
159
+ # @option opts [Hash] :data
160
+ # @option opts [Hash] :aria
161
+ # @option opts [Hash] :child
162
+ # @return [String]
163
+ #
164
+ def nav_item_with_wrapper(target, opts = {}, &block)
165
+ attrs = opts
166
+ child = attrs.delete(:child) { {} }.merge(@bs_attrs)
167
+ child[:class] = (child[:class] || '') << ' nav-link'
168
+
169
+ if attrs.fetch(:class, '').match?('active')
170
+ attrs[:class].gsub!('active', '')
171
+ child[:class] << ' active'
172
+ end
173
+
174
+ nav_item_wrapper(attrs) do
175
+ content_tag(
176
+ :a,
177
+ { href: "##{target}", tabindex: -1 }.merge(child)
178
+ ) do
179
+ block_given? ? block.call : target.to_s.titleize
180
+ end
181
+ end
182
+ end
183
+ # rubocop:enable Metrics/AbcSize
184
+
185
+ # @param [Symbol|String] target
186
+ # @param [Hash] opts
187
+ # @option opts [String] :id
188
+ # @option opts [String] :class
189
+ # @option opts [Hash] :data
190
+ # @option opts [Hash] :aria
191
+ # @return [String]
192
+ #
193
+ def nav_item_without_wrapper(target, opts = {}, &block)
194
+ attrs = opts.merge(@bs_attrs)
195
+ attrs[:class] = (attrs[:class] || '') << ' nav-link'
196
+
197
+ nav_item_wrapper do
198
+ content_tag(
199
+ :a,
200
+ { href: "##{target}", tabindex: -1 }.merge(attrs)
201
+ ) do
202
+ block_given? ? block.call : target.to_s.titleize
203
+ end
204
+ end
205
+ end
206
+
127
207
  # Decorator for elements requiring a wrapper component.
128
208
  #
129
209
  # @return [String]
130
210
  #
131
211
  def nav_item_wrapper(opts = {}, &block)
132
- id = opts.fetch(:id, '')
133
- klass = opts.fetch(:class, '')
134
- data = opts.fetch(:data, {})
212
+ opts[:class] = (opts[:class] || '') << ' nav-item'
135
213
 
136
214
  case @tag
137
215
  when :nav
138
216
  block.call
139
217
  when :ul
140
- content_tag(
141
- :li,
142
- id: id,
143
- class: "nav-item #{klass}",
144
- data: data,
145
- &block
146
- )
218
+ content_tag(:li, opts, &block)
147
219
  end
148
220
  end
149
221
  end
222
+ # rubocop:enable Metrics/ClassLength
150
223
  end
@@ -4,111 +4,112 @@ module Bootstrap5Helper
4
4
  #
5
5
  #
6
6
  class Content < Component
7
- # Constructor description...
8
- #
9
- #
10
7
  # @param [Hash] opts
11
8
  # @return [ClassName]
12
9
  #
13
10
  def initialize(template, opts = {}, &block)
14
11
  super(template)
15
12
 
16
- @id = opts.fetch(:id, uuid)
17
- @class = opts.fetch(:class, '')
18
- @data = opts.fetch(:data, {})
19
- @aria = opts.fetch(:aria, {})
20
- @scrollable = opts.fetch(:scrollable, false)
21
- @position = opts.fetch(:position, 'start')
22
- @backdrop = opts.fetch(:backdrop, true)
13
+ @attrs = opts
14
+ @id = @attrs.delete(:id) { uuid }
15
+ @class = @attrs.delete(:class) { '' }
16
+ @data = @attrs.delete(:data) { {} }
17
+ @aria = @attrs.delete(:aria) { {} }
18
+ @scrollable = @attrs.delete(:scrollable) { false }
19
+ @position = @attrs.delete(:position) { 'start' }
20
+ @backdrop = @attrs.delete(:backdrop) { true }
23
21
  @content = block || proc { '' }
24
22
  end
25
23
 
26
24
  # @todo
27
- #
28
- #
29
25
  def header(opts = {}, &block)
30
- id = opts.fetch(:id, nil)
31
- klass = opts.fetch(:class, '')
32
- data = opts.fetch(:data, {})
26
+ attrs = opts
27
+ id = attrs.delete(:id) { nil }
28
+ klass = attrs.delete(:class) { '' }
29
+ data = attrs.delete(:data) { {} }
33
30
 
34
31
  content_tag(
35
32
  config({ offcanvas: :header }, :div),
36
- id: id,
37
- class: "offcanvas-header #{klass}",
38
- data: data,
33
+ {
34
+ id: id,
35
+ class: "offcanvas-header #{klass}",
36
+ data: data
37
+ }.merge(attrs),
39
38
  &block
40
39
  )
41
40
  end
42
41
 
43
42
  # @todo
44
- #
45
- #
46
43
  def title(text_or_options = nil, opts = {}, &block)
47
- text, args = parse_text_or_options(text_or_options, opts)
44
+ text, attrs = parse_text_or_options(text_or_options, opts)
48
45
 
49
- id = args.fetch(:id, nil)
50
- klass = args.fetch(:class, '')
51
- data = args.fetch(:data, {})
46
+ id = attrs.delete(:id) { nil }
47
+ klass = attrs.delete(:class) { '' }
48
+ data = attrs.delete(:data) { {} }
52
49
 
53
50
  content_tag(
54
51
  config({ offcanvas: :title }, :h6),
55
52
  text,
56
- id: id,
57
- class: "offcanvas-title #{klass}",
58
- data: data,
53
+ {
54
+ id: id,
55
+ class: "offcanvas-title #{klass}",
56
+ data: data
57
+ }.merge(attrs),
59
58
  &block
60
59
  )
61
60
  end
62
61
 
63
62
  # @todo
64
- #
65
- #
66
63
  def close_button(opts = {})
67
- klass = opts.fetch(:class, '')
64
+ attrs = opts
65
+ klass = attrs.delete(:class) { '' }
66
+ data = attrs.delete(:data) { {} }
67
+ aria = attrs.delete(:aria) { {} }
68
68
 
69
69
  content_tag(
70
70
  config({ offcanvas: :close }, :button),
71
71
  class: block_given? ? klass : 'btn-close',
72
- data: { 'bs-dismiss': 'offcanvas' },
73
- aria: { label: 'Close' }
72
+ data: data.merge('bs-dismiss' => 'offcanvas'),
73
+ aria: aria.merge(label: 'Close')
74
74
  ) do
75
75
  block_given? ? yield : xbutton
76
76
  end
77
77
  end
78
78
 
79
79
  # @todo
80
- #
81
- #
82
80
  def body(opts = {}, &block)
83
- id = opts.fetch(:id, nil)
84
- klass = opts.fetch(:class, '')
85
- data = opts.fetch(:data, {})
86
- aria = opts.fetch(:aria, {})
81
+ attrs = opts
82
+ id = attrs.delete(:id) { nil }
83
+ klass = attrs.delete(:class) { '' }
84
+ data = attrs.delete(:data) { {} }
85
+ aria = attrs.delete(:aria) { {} }
87
86
 
88
87
  content_tag(
89
88
  :div,
90
- id: id,
91
- class: "offcanvas-body #{klass}",
92
- data: data,
93
- aria: aria,
89
+ {
90
+ id: id,
91
+ class: "offcanvas-body #{klass}",
92
+ data: data,
93
+ aria: aria
94
+ }.merge(attrs),
94
95
  &block
95
96
  )
96
97
  end
97
98
 
98
99
  # @todo
99
- #
100
- #
101
100
  def to_s
102
- @data.merge!('bs-scroll': @scrollable)
103
- @data.merge!('bs-backdrop': @backdrop)
104
-
105
101
  content_tag(
106
102
  :div,
107
- id: @id,
108
- class: "offcanvas offcanvas-#{@position} #{@class}",
109
- tabindex: -1,
110
- data: @data,
111
- aria: { labelledby: 'offcanvasExampleLabel' }
103
+ {
104
+ id: @id,
105
+ class: "offcanvas offcanvas-#{@position} #{@class}",
106
+ tabindex: -1,
107
+ data: @data.merge!(
108
+ 'bs-scroll' => @scrollable,
109
+ 'bs-backdrop' => @backdrop
110
+ ),
111
+ aria: @aria.merge!(labelledby: 'offcanvasExampleLabel')
112
+ }.merge(@attrs)
112
113
  ) do
113
114
  @content.call(self)
114
115
  end
@@ -18,14 +18,14 @@ module Bootstrap5Helper
18
18
  #
19
19
  def initialize(template, position_or_options = nil, opts = {}, &block)
20
20
  super(template)
21
- @pos, args = parse_position_or_options(position_or_options, opts)
22
- @id = args.fetch(:id, uuid)
23
- @class = args.fetch(:class, '')
24
- @data = args.fetch(:data, {})
25
- @aria = args.fetch(:aria, {})
26
- @scrollable = args.fetch(:scrollable, false)
27
- @backdrop = args.fetch(:backdrop, true)
28
- @content = block || proc { '' }
21
+ @pos, @attrs = parse_position_or_options(position_or_options, opts)
22
+ @id = @attrs.delete(:id) { uuid }
23
+ @class = @attrs.delete(:class) { '' }
24
+ @data = @attrs.delete(:data) { {} }
25
+ @aria = @attrs.delete(:aria) { {} }
26
+ @scrollable = @attrs.delete(:scrollable) { false }
27
+ @backdrop = @attrs.delete(:backdrop) { true }
28
+ @content = block || proc { '' }
29
29
  end
30
30
  # rubocop:disable Metrics/MethodLength
31
31
 
@@ -139,7 +139,7 @@ module Bootstrap5Helper
139
139
  scrollable: @scrollable,
140
140
  backdrop: @backdrop,
141
141
  position: @pos
142
- },
142
+ }.merge(@attrs),
143
143
  &block
144
144
  )
145
145
  end
@@ -1,8 +1,9 @@
1
+ # frozen_string_literal: false
2
+
1
3
  module Bootstrap5Helper
2
4
  class Overlay
5
+ # rubocop:disable Metrics/ClassLength
3
6
  # Builds a menu component for use in dropdowns.
4
- #
5
- #
6
7
  class Menu < Component
7
8
  # Class constructor
8
9
  #
@@ -17,9 +18,10 @@ module Bootstrap5Helper
17
18
  super(template)
18
19
 
19
20
  @tag, opts = parse_tag_or_options(*tag_or_options, {})
20
- @id = opts.fetch(:id, uuid)
21
- @class = opts.fetch(:class, '')
22
- @data = opts.fetch(:data, {})
21
+ @attrs = opts
22
+ @id = @attrs.delete(:id) { uuid }
23
+ @class = @attrs.delete(:class) { '' }
24
+ @data = @attrs.delete(:data) { {} }
23
25
  @content = block || proc { '' }
24
26
  end
25
27
 
@@ -45,8 +47,6 @@ module Bootstrap5Helper
45
47
  end
46
48
  end
47
49
 
48
- # rubocop:disable Metrics/MethodLength
49
-
50
50
  # Use this method when you are using the item in the menu as trigger for
51
51
  # something like tab content.
52
52
  #
@@ -59,25 +59,23 @@ module Bootstrap5Helper
59
59
  # @return [String]
60
60
  #
61
61
  def item(target, opts = {})
62
- id = opts.fetch(:id, nil)
63
- klass = opts.fetch(:class, '')
64
- data = opts.fetch(:data, {}).merge('bs-toggle' => 'tab')
65
- aria = opts.fetch(:aria, {})
62
+ attrs = opts
63
+ klass = attrs.delete(:class) { '' }
64
+ data = attrs.delete(:data) { {} }
66
65
 
67
66
  nav_item_wrapper do
68
67
  content_tag(
69
68
  :a,
70
- id: id,
71
- class: "dropdown-item #{klass}",
72
- href: "##{target}",
73
- aria: aria,
74
- data: data
69
+ {
70
+ class: "dropdown-item #{klass}",
71
+ href: "##{target}",
72
+ data: data.merge('bs-toggle' => 'tab')
73
+ }.merge(attrs)
75
74
  ) do
76
75
  block_given? ? yield : target.to_s.titleize
77
76
  end
78
77
  end
79
78
  end
80
- # rubocop:enable Metrics/MethodLength
81
79
 
82
80
  # Builds a Text component
83
81
  #
@@ -142,9 +140,11 @@ module Bootstrap5Helper
142
140
  def to_s
143
141
  content_tag(
144
142
  @tag || config({ overlay_menus: :base }, :div),
145
- id: @id,
146
- class: "dropdown-menu #{@class}",
147
- data: @data
143
+ {
144
+ id: @id,
145
+ class: "dropdown-menu #{@class}",
146
+ data: @data
147
+ }.merge(@attrs)
148
148
  ) do
149
149
  @content.call(self)
150
150
  end
@@ -177,19 +177,23 @@ module Bootstrap5Helper
177
177
  # @return [String]
178
178
  #
179
179
  def build_sub_component(tag, text, type, opts)
180
- id = opts.fetch(:id, nil)
181
- klass = opts.fetch(:class, '')
182
- data = opts.fetch(:data, {})
180
+ attrs = opts
181
+ id = attrs.delete(:id) { nil }
182
+ klass = attrs.delete(:class) { '' }
183
+ data = attrs.delete(:data) { {} }
183
184
 
184
185
  content_tag(
185
186
  tag,
186
- id: id,
187
- class: "dropdown-#{type} #{klass}",
188
- data: data
187
+ {
188
+ id: id,
189
+ class: "dropdown-#{type} #{klass}",
190
+ data: data
191
+ }.merge(attrs)
189
192
  ) do
190
193
  block_given? ? yield : text || ''
191
194
  end
192
195
  end
193
196
  end
197
+ # rubocop:enable Metrics/ClassLength
194
198
  end
195
199
  end
@@ -28,15 +28,18 @@ module Bootstrap5Helper
28
28
  super(template)
29
29
 
30
30
  @tag, args = parse_tag_or_options(*tag_or_options, {})
31
- @split = args.fetch(:split, false)
32
- @centered = args.fetch(:centered, false)
33
- @id = args.fetch(:id, uuid)
34
- @class = args.fetch(:class, '')
35
- @data = args.fetch(:data, {})
31
+ @attrs = args
32
+ @split = @attrs.delete(:split) { false }
33
+ @centered = @attrs.delete(:centered) { false }
34
+ @id = @attrs.delete(:id) { uuid }
35
+ @class = @attrs.delete(:class) { '' }
36
+ @data = @attrs.delete(:data) { {} }
36
37
 
37
38
  @content = block || proc { '' }
38
39
  end
39
40
 
41
+ # rubocop:disable Metrics/MethodLength
42
+
40
43
  # Used to generate a button for the dropdown. This button just
41
44
  # opens the coresponding dropdown menu.
42
45
  #
@@ -48,23 +51,29 @@ module Bootstrap5Helper
48
51
  # @return [String]
49
52
  #
50
53
  def button(context = :primary, opts = {}, &block)
51
- id = opts.fetch(:id, nil)
52
- klass = opts.fetch(:class, '')
53
- data = opts.fetch(:data, {}).merge(
54
- 'bs-toggle' => 'dropdown',
55
- 'bs-display' => 'static'
56
- )
54
+ attrs = opts
55
+ klass = attrs.delete(:class) { '' }
56
+ data = attrs.delete(:data) { {} }
57
+ aria = attrs.delete(:aria) { {} }
57
58
 
58
59
  content_tag(
59
60
  :button,
60
- id: id,
61
- type: 'button',
62
- class: "dropdown-toggle btn btn-#{context} #{klass}",
63
- data: data,
64
- aria: { haspopup: true, expanded: false },
61
+ {
62
+ type: 'button',
63
+ class: "dropdown-toggle btn btn-#{context} #{klass}",
64
+ data: data.merge(
65
+ 'bs-toggle' => 'dropdown',
66
+ 'bs-display' => 'static'
67
+ ),
68
+ aria: aria.merge(
69
+ haspopup: true,
70
+ expanded: false
71
+ )
72
+ }.merge(attrs),
65
73
  &block
66
74
  )
67
75
  end
76
+ # rubocop:enable Metrics/MethodLength
68
77
 
69
78
  # Used to generate a button with just the caret, to open the dropdown.
70
79
  #
@@ -112,9 +121,11 @@ module Bootstrap5Helper
112
121
  def to_s
113
122
  content_tag(
114
123
  @tag || :div,
115
- id: @id,
116
- class: "#{@type} #{alignment_type_class} #{@class}",
117
- data: @data
124
+ {
125
+ id: @id,
126
+ class: "#{@type} #{alignment_type_class} #{@class}",
127
+ data: @data
128
+ }.merge(@attrs)
118
129
  ) do
119
130
  @content.call(self)
120
131
  end
@@ -15,12 +15,12 @@ module Bootstrap5Helper
15
15
  def initialize(template, tag_or_options = nil, opts = {}, &block)
16
16
  super(template)
17
17
 
18
- @tag, args = parse_tag_or_options(tag_or_options, opts)
18
+ @tag, @attrs = parse_tag_or_options(tag_or_options, opts)
19
19
  @tag ||= config(:page_header, :h1)
20
20
 
21
- @id = args.fetch(:id, uuid)
22
- @class = args.fetch(:class, '')
23
- @data = args.fetch(:data, {})
21
+ @id = @attrs.delete(:id) { uuid }
22
+ @class = @attrs.delete(:class) { '' }
23
+ @data = @attrs.delete(:data) { {} }
24
24
  @content = block || proc { '' }
25
25
  end
26
26
 
@@ -31,9 +31,11 @@ module Bootstrap5Helper
31
31
  def to_s
32
32
  content_tag(
33
33
  @tag,
34
- id: @id,
35
- class: "pb-2 mt-4 mb-2 border-bottom #{@class}",
36
- data: @data
34
+ {
35
+ id: @id,
36
+ class: "pb-2 mt-4 mb-2 border-bottom #{@class}",
37
+ data: @data
38
+ }.merge(@attrs)
37
39
  ) do
38
40
  @content.call(self)
39
41
  end
@@ -18,11 +18,12 @@ module Bootstrap5Helper
18
18
  def initialize(template, opts = {}, &block)
19
19
  super(template)
20
20
 
21
- @type = opts.fetch(:type, :border)
22
- @size = opts.fetch(:size, nil)
23
- @id = opts.fetch(:id, uuid)
24
- @class = opts.fetch(:class, '')
25
- @data = opts.fetch(:data, {})
21
+ @attrs = opts
22
+ @type = @attrs.delete(:type) { :border }
23
+ @size = @attrs.delete(:size) { nil }
24
+ @id = @attrs.delete(:id) { uuid }
25
+ @class = @attrs.delete(:class) { '' }
26
+ @data = @attrs.delete(:data) { {} }
26
27
  @content = block || proc { '' }
27
28
  end
28
29
 
@@ -33,11 +34,13 @@ module Bootstrap5Helper
33
34
  def to_s
34
35
  content_tag(
35
36
  :span,
36
- id: @id,
37
- class: component_classes,
38
- role: 'status',
39
- aria: { hidden: true },
40
- data: @data
37
+ {
38
+ id: @id,
39
+ class: component_classes,
40
+ role: 'status',
41
+ aria: { hidden: true },
42
+ data: @data
43
+ }.merge(@attrs)
41
44
  ) do
42
45
  content_tag :span, 'Loading', class: 'visually-hidden'
43
46
  end
@@ -15,9 +15,10 @@ module Bootstrap5Helper
15
15
  def initialize(template, opts = {}, &block)
16
16
  super(template)
17
17
 
18
- @id = opts.fetch(:id, uuid)
19
- @class = opts.fetch(:class, '')
20
- @data = opts.fetch(:data, {})
18
+ @attrs = opts
19
+ @id = @attrs.delete(:id) { uuid }
20
+ @class = @attrs.delete(:class) { '' }
21
+ @data = @attrs.delete(:data) { {} }
21
22
  @content = block || proc { '' }
22
23
  end
23
24
 
@@ -30,16 +31,19 @@ module Bootstrap5Helper
30
31
  # @return [String]
31
32
  #
32
33
  def pane(source, opts = {}, &block)
33
- id = opts.fetch(:id, source)
34
- klass = opts.fetch(:class, '')
35
- data = opts.fetch(:data, {})
34
+ attrs = opts
35
+ id = attrs.delete(:id) { source }
36
+ klass = attrs.delete(:class) { '' }
37
+ data = attrs.delete(:data) { {} }
36
38
 
37
39
  content_tag(
38
40
  :div,
39
- id: id,
40
- class: "tab-pane #{klass}",
41
- role: 'tabpanel',
42
- data: data,
41
+ {
42
+ id: id,
43
+ class: "tab-pane #{klass}",
44
+ role: 'tabpanel',
45
+ data: data
46
+ }.merge(attrs),
43
47
  &block
44
48
  )
45
49
  end
@@ -49,7 +53,14 @@ module Bootstrap5Helper
49
53
  # @return [String]
50
54
  #
51
55
  def to_s
52
- content_tag :div, id: @id, class: "tab-content #{@class}" do
56
+ content_tag(
57
+ :div,
58
+ {
59
+ id: @id,
60
+ class: "tab-content #{@class}",
61
+ data: @data
62
+ }.merge(@attrs)
63
+ ) do
53
64
  @content.call(self)
54
65
  end
55
66
  end
@@ -30,14 +30,14 @@ module Bootstrap5Helper
30
30
  # @option opts [String] :id
31
31
  # @option opts [String] :class
32
32
  # @option opts [Hash] :data
33
- # @option opts [Hash] :child - data attributes for child, NOT wrapper
33
+ # @option opts [Hash] :bs_attrs
34
34
  #
35
35
  # @overload nav(opts)
36
36
  # @param [Hash] opts
37
37
  # @option opts [String] :id
38
38
  # @option opts [String] :class
39
39
  # @option opts [Hash] :data
40
- # @option opts [Hash] :child - data attributes for child, NOT wrapper
40
+ # @option opts [Hash] :bs_attrs
41
41
  #
42
42
  # @yield [Nav]
43
43
  # @return [Nav]
@@ -45,9 +45,14 @@ module Bootstrap5Helper
45
45
  def nav(*tag_or_options, &block)
46
46
  tag, args = parse_tag_or_options(*tag_or_options, {})
47
47
 
48
- args[:class] = (args[:class] || '') << " nav-#{@type}"
49
- args[:data] = (args[:data] || {}).merge('bs-toggle' => 'tab')
50
- args[:child] = { data: { 'bs-toggle' => 'tab' } }
48
+ args[:class] = (args[:class] || '') << " nav-#{@type}"
49
+ args[:data] = (args[:data] || {})
50
+ args[:bs_attrs] = {
51
+ data: {
52
+ 'bs-toggle' => 'tab',
53
+ 'bs-display' => 'static'
54
+ }
55
+ }
51
56
 
52
57
  Nav.new(@template, tag, args, &block)
53
58
  end
@@ -1,3 +1,3 @@
1
1
  module Bootstrap5Helper
2
- VERSION = '1.2.1'.freeze
2
+ VERSION = '2.0.0.beta'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bootstrap5_helper
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 2.0.0.beta
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert David