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.
- checksums.yaml +4 -4
- data/README.md +69 -10
- data/app/components/bs5/expandable_list/group_component.html.erb +9 -0
- data/app/components/bs5/expandable_list/group_component.rb +43 -0
- data/app/components/bs5/expandable_list/group_item_component.html.erb +15 -0
- data/app/components/bs5/expandable_list/group_item_component.rb +100 -0
- data/app/components/bs5/{expandable_list_item_header_actions_component.html.erb → expandable_list/group_item_header/actions_component.html.erb} +1 -1
- data/app/components/bs5/expandable_list/group_item_header/actions_component.rb +18 -0
- data/app/components/bs5/{expandable_list_item_header_title_component.html.erb → expandable_list/group_item_header/title_component.html.erb} +2 -2
- data/app/components/bs5/expandable_list/group_item_header/title_component.rb +27 -0
- data/app/helpers/bs5_expandable_list_group/view_components_helper.rb +7 -1
- data/lib/bs5_expandable_list_group/version.rb +1 -1
- data/lib/generators/bs5_expandable_list_group/install/templates/controllers/stretchable_item_controller.js +1 -2
- data/lib/generators/bs5_expandable_list_group/install/templates/stylesheets/_expandable-items.scss +15 -7
- metadata +10 -10
- data/app/components/bs5/expandable_list_group_component.html.erb +0 -5
- data/app/components/bs5/expandable_list_group_component.rb +0 -41
- data/app/components/bs5/expandable_list_item_component.html.erb +0 -15
- data/app/components/bs5/expandable_list_item_component.rb +0 -74
- data/app/components/bs5/expandable_list_item_header_actions_component.rb +0 -14
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d0fe287158fb9bd8dc214ab834588e700e6a1c87c13410afa2761f6200a34dc8
|
4
|
+
data.tar.gz: 20e7875417d6b574f86c92e6c70595cad7cfd555ebbbde4f68e9c7bdf082d661
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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 `
|
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
|
-
|
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
|
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 `
|
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
|
-
| `
|
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,
|
280
|
+
<%= bs5_expandable_list_group(accordion: true, stretchable: true) do |c| %>
|
222
281
|
...
|
223
282
|
<% end %>
|
224
283
|
```
|
@@ -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-
|
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-
|
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::
|
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
|
@@ -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 = ["
|
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
|
}
|
data/lib/generators/bs5_expandable_list_group/install/templates/stylesheets/_expandable-items.scss
CHANGED
@@ -3,7 +3,14 @@
|
|
3
3
|
position: relative;
|
4
4
|
cursor: pointer;
|
5
5
|
|
6
|
-
&-
|
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-
|
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
|
-
|
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-
|
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-
|
26
|
-
|
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
|
+
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-
|
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/
|
104
|
-
- app/components/bs5/
|
105
|
-
- app/components/bs5/
|
106
|
-
- app/components/bs5/
|
107
|
-
- app/components/bs5/
|
108
|
-
- app/components/bs5/
|
109
|
-
- app/components/bs5/
|
110
|
-
- app/components/bs5/
|
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,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,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
|