bs5_expandable_list_group 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (21) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +69 -10
  3. data/app/components/bs5/expandable_list/group_component.html.erb +9 -0
  4. data/app/components/bs5/expandable_list/group_component.rb +43 -0
  5. data/app/components/bs5/expandable_list/group_item_component.html.erb +15 -0
  6. data/app/components/bs5/expandable_list/group_item_component.rb +100 -0
  7. data/app/components/bs5/{expandable_list_item_header_actions_component.html.erb → expandable_list/group_item_header/actions_component.html.erb} +1 -1
  8. data/app/components/bs5/expandable_list/group_item_header/actions_component.rb +18 -0
  9. data/app/components/bs5/{expandable_list_item_header_title_component.html.erb → expandable_list/group_item_header/title_component.html.erb} +2 -2
  10. data/app/components/bs5/expandable_list/group_item_header/title_component.rb +27 -0
  11. data/app/helpers/bs5_expandable_list_group/view_components_helper.rb +7 -1
  12. data/lib/bs5_expandable_list_group/version.rb +1 -1
  13. data/lib/generators/bs5_expandable_list_group/install/templates/controllers/stretchable_item_controller.js +1 -2
  14. data/lib/generators/bs5_expandable_list_group/install/templates/stylesheets/_expandable-items.scss +15 -7
  15. metadata +10 -10
  16. data/app/components/bs5/expandable_list_group_component.html.erb +0 -5
  17. data/app/components/bs5/expandable_list_group_component.rb +0 -41
  18. data/app/components/bs5/expandable_list_item_component.html.erb +0 -15
  19. data/app/components/bs5/expandable_list_item_component.rb +0 -74
  20. data/app/components/bs5/expandable_list_item_header_actions_component.rb +0 -14
  21. data/app/components/bs5/expandable_list_item_header_title_component.rb +0 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fb85128dd2e5cbcfadab803722f3641dc1f899d48f7648967790c4c07167e53e
4
- data.tar.gz: 7e35116c8fd0739e75387b65d99b071d68b4b99de79df9aeb2b538e37a94e9e9
3
+ metadata.gz: d0fe287158fb9bd8dc214ab834588e700e6a1c87c13410afa2761f6200a34dc8
4
+ data.tar.gz: 20e7875417d6b574f86c92e6c70595cad7cfd555ebbbde4f68e9c7bdf082d661
5
5
  SHA512:
6
- metadata.gz: 2020c90cf7b667d478018ed5d508b58167f28303f82bb79e9fb36010499e1e54e5e1bed16c13ce9408b7813363baad4a46322b250d232be895166e0c26eb41e8
7
- data.tar.gz: 0b380cdc5f32d767177cb16e2bd72b7df0088f41b23eb706591654d37dfd96bd8c035b11a4ea2f6175bc0c04238d4140521d6dd8f42815027a9b37fdd3856351
6
+ metadata.gz: 9ae2e083544567258691eb1a6d0b60b4c43de0bc7c9bbe4dbabb98d46e9df9c7d06c67b9febbd2daa156bee4a863a63f1a1e05fa31649ab11f960867ebd22fe7
7
+ data.tar.gz: 80aee9b9c941a123cde3190788c6d1e528ea65aff3eea285197edddb3627818ae8f86ab3daeb8cf0d1da5f5ba833caa779dad6a7a9eca090cfcef48c7f51bbbf
data/README.md CHANGED
@@ -66,7 +66,7 @@ Stylesheets are copied to `app/javascript/stylesheets`. If needed, you can add t
66
66
 
67
67
  ## Usage
68
68
 
69
- To render a **Bootstrap 5 expandable list group** you use `render(Bs5::ExpandableListGroupComponent.new)` and pass it a block for rendering every list item.
69
+ To render a **Bootstrap 5 expandable list group** you use `bs5_expandable_list_group` and pass it a block for rendering every list item.
70
70
 
71
71
  Given that you have assigned a list of `Post` instances to `@posts`, to render these `@posts` in a **Bootstrap 5 expandable list group**, you put the following code in your template:
72
72
 
@@ -160,7 +160,25 @@ To show a different set on hovering:
160
160
  <% end %>
161
161
  ```
162
162
 
163
- ### Omitting the `item` methods
163
+ #### Bypassing the hover behaviour
164
+
165
+ By default, when an item is collapsed, actions only show when you hover your mouse over the item. Since we use the `visibility` CSS property for this, you can bypass this behaviour one or more actions by setting its `visibility` property to `visible`. The following example uses the [`visible` utility](https://getbootstrap.com/docs/5.0/utilities/visibility/) from Bootstrap 5, but of course you can also use CSS:
166
+
167
+ ```erb
168
+ ...
169
+ <% c.item do |i| %>
170
+ <%= i.title do |t| %>
171
+ ...
172
+ <% end %>
173
+ <% i.actions do |a| %>
174
+ <%= link_to 'Not so important link', ... %>
175
+ <%= link_to 'Very important link', ..., class: 'visible` %>
176
+ <% end %>
177
+ <%= i.body { ... } %>
178
+ <% end %>
179
+ ```
180
+
181
+ ### Omitting the `item`'s methods
164
182
 
165
183
  Instead of using the `item`'s methods `title`, `body` and/or `actions` you can just use (HTML-) text as a block.
166
184
  This will render just a [list group item](https://getbootstrap.com/docs/5.0/components/list-group/#basic-example), but will come in handy when you, i.e. show the first 25 items of a longer list and want to present a "Load more" link as last item of the list (for simplicity sake the sample uses a non-working `link_to_next_page` although this is [part of Kaminari](https://github.com/kaminari/kaminari#the-link_to_next_page-and-link_to_previous_page-aliased-to-link_to_prev_page-helper-methods)):
@@ -181,9 +199,49 @@ This will render just a [list group item](https://getbootstrap.com/docs/5.0/comp
181
199
  <% end %>
182
200
  ```
183
201
 
202
+ ### Omitting the `item`
203
+
204
+ Instead of calling the `item` method on the yielded component, when you pass a block, it's rendered wrapped in the container element:
205
+
206
+ ```erb
207
+ <%= bs5_expandable_list_group do %>
208
+ <%= render @posts %>
209
+ <% end %>
210
+ ```
211
+
212
+ This will give you the same results as wrapping the posts in a `div` with the class **list-group**, but you can still pass other options to the `bs5_expandable_list_group` (although not all of them will be effective).
213
+
214
+ ### Rendering a single item
215
+
216
+ By calling the `item` method on the passed component you can render an item. But this can also be achieved outside the block by using the `bs5_expandable_list_group_item` helper method. The following snippet has the same result as other examples, but it does not use the `bs5_expandable_list_group` method:
217
+
218
+ ```erb
219
+ <div id="posts" class="list-group">
220
+ <% @posts.each do |post| %>
221
+ <% bs5_expandable_list_group_item(parent_id: 'posts') do |i| %>
222
+ <%= i.title { post.title } %>
223
+ <%= i.body { post.text } %>
224
+ <% end %>
225
+ <% end %>
226
+ </div>
227
+ ```
228
+
229
+ An application for rendering a single item is when you want to update an item without doing a full page reload by sending a response that contains only the list item and use JavaScript or (preferably) [Turbo](https://turbo.hotwire.dev/) to update the page.
230
+
231
+ #### Passing options
232
+
233
+ The following options can be passed to `bs5_expandable_list_group_item`:
234
+
235
+ | name | default | description |
236
+ |---|---|---|
237
+ | `tag` | `:div` | A symbol or string of a valid HTML tag that is used for the tag of the list item. |
238
+ | `parent_id` | | ID of a parent element to add accordion-like behaviour. |
239
+ | `stretchable` | `false` | Expanded items are shown a little bit bigger as if they come out a bit. |
240
+
241
+
184
242
  ### Wrap an item in an extra element
185
243
 
186
- Every list item is a `div` with one or more CSS classes and, dependent on block passed, some `data` attributes and is not customizable (yet).
244
+ Every list item is a `div` (or the element specified with `tag`) with one or more CSS classes and, dependent on block passed, some `data` attributes.
187
245
  However, you can wrap a list item in a extra element by passing a `wrapper_html` option to the `item` method:
188
246
 
189
247
  ```erb
@@ -205,20 +263,21 @@ All options passed to the item method are used as HTML attributes of the wrapper
205
263
 
206
264
  ### Passing options
207
265
 
208
- The following options can be passed to `Bs5::ExpandableListGroupComponent.new`:
266
+ The following options can be passed to `bs5_expandable_list_group`:
209
267
 
210
268
  | name | default | description |
211
269
  |---|---|---|
212
- | `tag` | `:div` | A symbol or string of a valid HTML tag that is used for the tag of the list group |
213
- | `id` | | is used to assign an id HTML attribute to the rendered container |
214
- | `class` | | is added to the class attribute of the rendered container |
215
- | `accordion` | `false` | Behaves as an Bootstrap [accordion](https://getbootstrap.com/docs/5.0/components/accordion/) by having only 1 item expanded |
216
- | `expandable` | `false` | Expanded items are shown a little bit bigger as if they come out a bit|
270
+ | `tag` | `:div` | A symbol or string of a valid HTML tag that is used for the tag of the list group. |
271
+ | `id` | | is used to assign an id HTML attribute to the rendered container. |
272
+ | `class` | | is added to the class attribute of the rendered container. |
273
+ | `accordion` | `false` | Behaves as an Bootstrap [accordion](https://getbootstrap.com/docs/5.0/components/accordion/) by having only 1 item expanded (only effective when used with `item` in the passed block). |
274
+ | `stretchable` | `false` | Expanded items are shown a little bit bigger as if they come out a bit. |
275
+ | `expanded` | `false` | Show the item expanded. |
217
276
 
218
277
  Example:
219
278
 
220
279
  ```erb
221
- <%= bs5_expandable_list_group(accordion: true, expandable: true) do |c| %>
280
+ <%= bs5_expandable_list_group(accordion: true, stretchable: true) do |c| %>
222
281
  ...
223
282
  <% end %>
224
283
  ```
@@ -0,0 +1,9 @@
1
+ <%= tag.send(tag_name, **component_attributes) do %>
2
+ <% if items.any? %>
3
+ <% items.each do |item| %>
4
+ <%= item %>
5
+ <% end %>
6
+ <% else %>
7
+ <%= content %>
8
+ <% end %>
9
+ <% end %>
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bs5
4
+ module ExpandableList
5
+ class GroupComponent < ViewComponent::Base
6
+ renders_many :items, lambda { |options = {}|
7
+ options.merge!(parent_id: id, stretchable: stretchable?)
8
+ GroupItemComponent.new(**options)
9
+ }
10
+
11
+ attr_reader :options, :is_accordion, :is_stretchable, :tag_name
12
+
13
+ DEFAULT_TAG_NAME = :div
14
+
15
+ def initialize(options = {})
16
+ @is_accordion = options.delete(:accordion)
17
+ @is_stretchable = options.delete(:stretchable)
18
+ @id = options.delete(:id)
19
+ @tag_name = options.delete(:tag) || DEFAULT_TAG_NAME
20
+ @options = options
21
+ end
22
+
23
+ private
24
+
25
+ def id
26
+ @id || (accordion? && "list-group-#{object_id}")
27
+ end
28
+
29
+ def component_class
30
+ ['list-group'].tap do |arr|
31
+ arr << @options[:class]
32
+ end
33
+ end
34
+
35
+ def component_attributes
36
+ options.merge(id: id, class: component_class)
37
+ end
38
+
39
+ alias accordion? is_accordion
40
+ alias stretchable? is_stretchable
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,15 @@
1
+ <%= wrapper do %>
2
+ <% if simple_content? %>
3
+ <%= tag.send(tag_name, content, **component_attributes) %>
4
+ <% else %>
5
+ <%= tag.send(tag_name, **component_attributes) do %>
6
+ <div class="expandable-item-header">
7
+ <%= title %>
8
+ <%= actions %>
9
+ </div>
10
+ <%= tag.div(id: target_id, class: body_class, data: body_data_options) do %>
11
+ <%= body %>
12
+ <% end %>
13
+ <% end %>
14
+ <% end %>
15
+ <% end %>
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bs5
4
+ module ExpandableList
5
+ class GroupItemComponent < ViewComponent::Base
6
+ DEFAULT_WRAPPER_TAG = :div
7
+ DEFAULT_TAG_NAME = :div
8
+ renders_one :title, lambda {
9
+ GroupItemHeader::TitleComponent.new(target_id: target_id, expanded: expanded?)
10
+ }
11
+ renders_one :actions, GroupItemHeader::ActionsComponent
12
+ renders_one :body
13
+
14
+ attr_reader :parent_id, :is_stretchable, :is_expanded, :tag_name, :wrapper_html, :options
15
+
16
+ def initialize(options = {})
17
+ @parent_id = options.delete(:parent_id)
18
+ @is_stretchable = options.delete(:stretchable)
19
+ @is_expanded = options.delete(:expanded)
20
+ @tag_name = options.delete(:tag) || DEFAULT_TAG_NAME
21
+ @wrapper_html = options.delete(:wrapper_html)
22
+ @options = options
23
+ end
24
+
25
+ private
26
+
27
+ def wrapper_html?
28
+ @wrapper_html.present?
29
+ end
30
+
31
+ def wrapper_tag
32
+ @wrapper_html.delete(:tag) || DEFAULT_WRAPPER_TAG
33
+ end
34
+
35
+ def wrapper(&block)
36
+ if wrapper_html?
37
+ tag.send(wrapper_tag, **wrapper_html, &block)
38
+ else
39
+ capture { block.call }
40
+ end
41
+ end
42
+
43
+ def simple_content?
44
+ title.blank? && body.blank? && actions.blank?
45
+ end
46
+
47
+ def target_id
48
+ "expandable-list-item-#{object_id}"
49
+ end
50
+
51
+ def body_data_options
52
+ {}.tap do |h|
53
+ h['bs-parent'] = "##{parent_id}" if parent_id
54
+ end
55
+ end
56
+
57
+ def component_data_options
58
+ {}.tap do |h|
59
+ h.merge!(stimulus_attributes) if stretchable?
60
+ end
61
+ end
62
+
63
+ def component_class
64
+ ['list-group-item'].tap do |arr|
65
+ arr << 'expandable-item' unless simple_content?
66
+ arr << 'stretchable-item'
67
+ arr << 'stretched' if !simple_content? && expanded?
68
+ end
69
+ end
70
+
71
+ def body_class
72
+ %w[expandable-item-body collapse].tap do |arr|
73
+ arr << 'show' if expanded?
74
+ end
75
+ end
76
+
77
+ def component_attributes
78
+ options.tap do |h|
79
+ h[:class] = component_class
80
+ h[:data] = component_data_options unless simple_content?
81
+ end
82
+ end
83
+
84
+ def stimulus_attributes
85
+ {
86
+ controller: stimulus_controller,
87
+ "#{stimulus_controller}-target": 'container',
88
+ "#{stimulus_controller}-stretched-class": 'stretched'
89
+ }
90
+ end
91
+
92
+ def stimulus_controller
93
+ 'stretchable-item'
94
+ end
95
+
96
+ alias stretchable? is_stretchable
97
+ alias expanded? is_expanded
98
+ end
99
+ end
100
+ end
@@ -1,6 +1,6 @@
1
1
  <div class="expandable-item-header-actions">
2
2
  <% if variable_actions? %>
3
- <%= tag.div(class: "expandable-item-header-actions-collaped") do %>
3
+ <%= tag.div(class: "expandable-item-header-actions-collapsed") do %>
4
4
  <%= collapsed %>
5
5
  <% end %>
6
6
  <%= tag.div(class: "expandable-item-header-actions-expanded") do %>
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bs5
4
+ module ExpandableList
5
+ module GroupItemHeader
6
+ class ActionsComponent < ViewComponent::Base
7
+ renders_one :collapsed
8
+ renders_one :expanded
9
+
10
+ private
11
+
12
+ def variable_actions?
13
+ collapsed || expanded
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,6 +1,6 @@
1
- <%= tag.div(class: "expandable-item-header-title", data: { "bs-toggle": :collapse, "bs-target": "##{target_id}" } ) do %>
1
+ <%= tag.div(class: "expandable-item-header-title", data: { "bs-toggle": :collapse, "bs-target": "##{target_id}" }, aria: { expanded: expanded? } ) do %>
2
2
  <% if variable_title? %>
3
- <%= tag.div(class: "expandable-item-header-title-collaped") do %>
3
+ <%= tag.div(class: "expandable-item-header-title-collapsed") do %>
4
4
  <%= collapsed %>
5
5
  <% end %>
6
6
  <%= tag.div(class: "expandable-item-header-title-expanded") do %>
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bs5
4
+ module ExpandableList
5
+ module GroupItemHeader
6
+ class TitleComponent < ViewComponent::Base
7
+ renders_one :collapsed
8
+ renders_one :expanded
9
+
10
+ attr_reader :target_id, :is_expanded
11
+
12
+ def initialize(target_id:, expanded: false)
13
+ @target_id = target_id
14
+ @is_expanded = expanded
15
+ end
16
+
17
+ private
18
+
19
+ def variable_title?
20
+ collapsed || expanded
21
+ end
22
+
23
+ alias expanded? is_expanded
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,7 +1,13 @@
1
1
  module Bs5ExpandableListGroup
2
2
  module ViewComponentsHelper
3
3
  def bs5_expandable_list_group(*args)
4
- render ::Bs5::ExpandableListGroupComponent.new(*args) do |c|
4
+ render ::Bs5::ExpandableList::GroupComponent.new(*args) do |c|
5
+ yield c if block_given?
6
+ end
7
+ end
8
+
9
+ def bs5_expandable_list_group_item(*args)
10
+ render ::Bs5::ExpandableList::GroupItemComponent.new(*args) do |c|
5
11
  yield c if block_given?
6
12
  end
7
13
  end
@@ -1,3 +1,3 @@
1
1
  module Bs5ExpandableListGroup
2
- VERSION = '0.4.0'
2
+ VERSION = '0.5.0'
3
3
  end
@@ -5,7 +5,7 @@ const HIDE_EVENT = "hide.bs.collapse";
5
5
 
6
6
  export default class extends Controller {
7
7
  static targets = ["container"];
8
- static classes = ["item", "stretched"];
8
+ static classes = ["stretched"];
9
9
 
10
10
  initialize() {
11
11
  this.onShow = this._onShow.bind(this);
@@ -14,7 +14,6 @@ export default class extends Controller {
14
14
  }
15
15
 
16
16
  connect() {
17
- this.containerTarget.classList.add(this.itemClass);
18
17
  this.contentNode.addEventListener(SHOW_EVENT, this.onShow);
19
18
  this.contentNode.addEventListener(HIDE_EVENT, this.onHide);
20
19
  }
@@ -3,7 +3,14 @@
3
3
  position: relative;
4
4
  cursor: pointer;
5
5
 
6
- &-actions {
6
+ &-title-expanded {
7
+ position: absolute;
8
+ top: 0;
9
+ right: 0;
10
+ left: 0;
11
+ }
12
+
13
+ &-actions-collapsed, &-actions-expanded {
7
14
  position: absolute;
8
15
  top: 0;
9
16
  right: 0;
@@ -12,17 +19,18 @@
12
19
 
13
20
  &:hover &-header-actions,
14
21
  &-header-title[aria-expanded="true"] &-header-title-expanded,
15
- &-header-title:not([aria-expanded="true"]) &-header-title-collaped,
22
+ &-header-title:not([aria-expanded="true"]) &-header-title-collapsed,
16
23
  &-header-title[aria-expanded="true"] + &-header-actions,
17
- &-header-title[aria-expanded="true"] + &-header-actions &-header-actions-expanded {
18
- display: revert;
24
+ &-header-title[aria-expanded="true"] + &-header-actions &-header-actions-expanded,
25
+ &-header-actions :focus-within {
26
+ visibility: visible;
19
27
  }
20
28
 
21
29
  &-header &-header-actions,
22
- &-header-title[aria-expanded="true"] &-header-title-collaped,
30
+ &-header-title[aria-expanded="true"] &-header-title-collapsed,
23
31
  &-header-title:not([aria-expanded="true"]) &-header-title-expanded,
24
32
  &-header-actions-expanded,
25
- &-header-title[aria-expanded="true"] + &-header-actions &-header-actions-collaped {
26
- display: none;
33
+ &-header-title[aria-expanded="true"] + &-header-actions &-header-actions-collapsed {
34
+ visibility: hidden;
27
35
  }
28
36
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bs5_expandable_list_group
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patrick Baselier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-03 00:00:00.000000000 Z
11
+ date: 2021-06-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -100,14 +100,14 @@ files:
100
100
  - Rakefile
101
101
  - app/assets/config/bs5_expandable_list_group_manifest.js
102
102
  - app/assets/stylesheets/bs5_expandable_list_group/application.css
103
- - app/components/bs5/expandable_list_group_component.html.erb
104
- - app/components/bs5/expandable_list_group_component.rb
105
- - app/components/bs5/expandable_list_item_component.html.erb
106
- - app/components/bs5/expandable_list_item_component.rb
107
- - app/components/bs5/expandable_list_item_header_actions_component.html.erb
108
- - app/components/bs5/expandable_list_item_header_actions_component.rb
109
- - app/components/bs5/expandable_list_item_header_title_component.html.erb
110
- - app/components/bs5/expandable_list_item_header_title_component.rb
103
+ - app/components/bs5/expandable_list/group_component.html.erb
104
+ - app/components/bs5/expandable_list/group_component.rb
105
+ - app/components/bs5/expandable_list/group_item_component.html.erb
106
+ - app/components/bs5/expandable_list/group_item_component.rb
107
+ - app/components/bs5/expandable_list/group_item_header/actions_component.html.erb
108
+ - app/components/bs5/expandable_list/group_item_header/actions_component.rb
109
+ - app/components/bs5/expandable_list/group_item_header/title_component.html.erb
110
+ - app/components/bs5/expandable_list/group_item_header/title_component.rb
111
111
  - app/controllers/bs5_expandable_list_group/application_controller.rb
112
112
  - app/helpers/bs5_expandable_list_group/application_helper.rb
113
113
  - app/helpers/bs5_expandable_list_group/view_components_helper.rb
@@ -1,5 +0,0 @@
1
- <%= tag.send(tag_name, **component_attributes) do %>
2
- <% items.each do |item| %>
3
- <%= item %>
4
- <% end %>
5
- <% end %>
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Bs5
4
- class ExpandableListGroupComponent < ViewComponent::Base
5
- renders_many :items, lambda { |options = {}|
6
- options.merge!(parent_id: id, stretchable: stretchable?)
7
- ExpandableListItemComponent.new(**options)
8
- }
9
-
10
- attr_reader :options, :accordion, :stretchable, :tag_name
11
-
12
- DEFAULT_TAG_NAME = :div
13
-
14
- def initialize(options = {})
15
- @accordion = options.delete(:accordion)
16
- @stretchable = options.delete(:stretchable)
17
- @id = options.delete(:id)
18
- @tag_name = options.delete(:tag) || DEFAULT_TAG_NAME
19
- @options = options
20
- end
21
-
22
- private
23
-
24
- def id
25
- @id || (accordion? && "list-group-#{object_id}")
26
- end
27
-
28
- def component_class
29
- class_names = ['list-group']
30
- class_names << @options[:class]
31
- class_names
32
- end
33
-
34
- def component_attributes
35
- options.merge(id: id, class: component_class)
36
- end
37
-
38
- alias accordion? accordion
39
- alias stretchable? stretchable
40
- end
41
- end
@@ -1,15 +0,0 @@
1
- <%= wrapper do %>
2
- <% if simple_content? %>
3
- <%= tag.div(content, class: "list-group-item") %>
4
- <% else %>
5
- <%= tag.div(class: "list-group-item expandable-item", data: component_data_options) do %>
6
- <div class="expandable-item-header">
7
- <%= title %>
8
- <%= actions %>
9
- </div>
10
- <%= tag.div(id: target_id, class: "expandable-item-body collapse", data: body_data_options) do %>
11
- <%= body %>
12
- <% end %>
13
- <% end %>
14
- <% end %>
15
- <% end %>
@@ -1,74 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Bs5
4
- class ExpandableListItemComponent < ViewComponent::Base
5
- DEFAULT_WRAPPER_TAG = :div
6
- renders_one :title, lambda {
7
- ExpandableListItemHeaderTitleComponent.new(target_id: target_id)
8
- }
9
- renders_one :actions, ExpandableListItemHeaderActionsComponent
10
- renders_one :body
11
-
12
- attr_reader :parent_id, :stretchable, :wrapper_html
13
-
14
- def initialize(options = {})
15
- @parent_id = options.delete(:parent_id)
16
- @stretchable = options.delete(:stretchable)
17
- @wrapper_html = options.delete(:wrapper_html)
18
- @options = options
19
- end
20
-
21
- private
22
-
23
- def wrapper_html?
24
- @wrapper_html.present?
25
- end
26
-
27
- def wrapper_tag
28
- @wrapper_html.delete(:tag) || DEFAULT_WRAPPER_TAG
29
- end
30
-
31
- def wrapper(&block)
32
- if wrapper_html?
33
- tag.send(wrapper_tag, **wrapper_html, &block)
34
- else
35
- capture { block.call }
36
- end
37
- end
38
-
39
- def simple_content?
40
- title.blank? && body.blank? && actions.blank?
41
- end
42
-
43
- def target_id
44
- "expandable-list-item-#{object_id}"
45
- end
46
-
47
- def body_data_options
48
- {}.tap do |h|
49
- h['bs-parent'] = "##{parent_id}" if parent_id
50
- end
51
- end
52
-
53
- def component_data_options
54
- {}.tap do |h|
55
- h.merge!(stimulus_attributes) if stretchable?
56
- end
57
- end
58
-
59
- def stimulus_attributes
60
- {
61
- controller: stimulus_controller,
62
- "#{stimulus_controller}-target": 'container',
63
- "#{stimulus_controller}-item-class": 'stretchable-item',
64
- "#{stimulus_controller}-stretched-class": 'stretched'
65
- }
66
- end
67
-
68
- def stimulus_controller
69
- 'stretchable-item'
70
- end
71
-
72
- alias stretchable? stretchable
73
- end
74
- end
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Bs5
4
- class ExpandableListItemHeaderActionsComponent < ViewComponent::Base
5
- renders_one :collapsed
6
- renders_one :expanded
7
-
8
- private
9
-
10
- def variable_actions?
11
- collapsed || expanded
12
- end
13
- end
14
- end
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Bs5
4
- class ExpandableListItemHeaderTitleComponent < ViewComponent::Base
5
- renders_one :collapsed
6
- renders_one :expanded
7
-
8
- attr_reader :target_id
9
-
10
- def initialize(target_id:)
11
- @target_id = target_id
12
- end
13
-
14
- private
15
-
16
- def variable_title?
17
- collapsed || expanded
18
- end
19
- end
20
- end