bs5_expandable_list_group 0.1.0 → 0.5.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.
- checksums.yaml +4 -4
- data/README.md +124 -20
- 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 +15 -0
- data/lib/bs5_expandable_list_group/engine.rb +5 -0
- 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 +17 -13
- data/app/components/bs5/expandable_list_group_component.html.erb +0 -5
- data/app/components/bs5/expandable_list_group_component.rb +0 -33
- data/app/components/bs5/expandable_list_item_component.html.erb +0 -9
- data/app/components/bs5/expandable_list_item_component.rb +0 -52
- 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
@@ -1,15 +1,16 @@
|
|
1
1
|
# Bootstrap 5 expandable list group
|
2
2
|
|
3
3
|
[](https://travis-ci.org/bazzel/Bs5ExpandableListGroup)
|
4
|
+
[](https://badge.fury.io/rb/bs5_expandable_list_group)
|
4
5
|
|
5
|
-
**Bootstrap 5 expandable list group** gives you a simple API for creating expandable and stretchable list groups. A bit like [Bootstrap 5](https://getbootstrap.com/)'s [Accordion](https://getbootstrap.com/docs/5.0/components/accordion/), [Collapse](https://getbootstrap.com/docs/5.0/components/collapse/) and [List group](https://getbootstrap.com/docs/5.0/components/list-group/) components combined.
|
6
|
+
**Bootstrap 5 expandable list group** is a Ruby on Rails engine and gives you a simple API for creating expandable and stretchable list groups. A bit like [Bootstrap 5](https://getbootstrap.com/)'s [Accordion](https://getbootstrap.com/docs/5.0/components/accordion/), [Collapse](https://getbootstrap.com/docs/5.0/components/collapse/) and [List group](https://getbootstrap.com/docs/5.0/components/list-group/) components combined.
|
6
7
|
|
7
8
|
https://user-images.githubusercontent.com/7672/120296188-27170580-c2c8-11eb-936a-a93c16326acb.mp4
|
8
9
|
|
9
10
|
## TL;DR
|
10
11
|
|
11
12
|
```erb
|
12
|
-
<%=
|
13
|
+
<%= bs5_expandable_list_group do |c| %>
|
13
14
|
<% @posts.each do |post| %>
|
14
15
|
<% c.item do |i| %>
|
15
16
|
<%= i.title { post.title } %>
|
@@ -55,7 +56,7 @@ $ bin/rails generate bs5_expandable_list_group:install
|
|
55
56
|
|
56
57
|
This copies the required assets to your application directory:
|
57
58
|
|
58
|
-
Stylesheets are copied to `app/javascript/stylesheets`. If needed, you can the following line to your `application.scss` to import them:
|
59
|
+
Stylesheets are copied to `app/javascript/stylesheets`. If needed, you can add the following line to your `application.scss` to import them:
|
59
60
|
|
60
61
|
```scss
|
61
62
|
@import "bootstrap";
|
@@ -63,16 +64,14 @@ Stylesheets are copied to `app/javascript/stylesheets`. If needed, you can the f
|
|
63
64
|
@import "stylesheets/stretchable-items";
|
64
65
|
```
|
65
66
|
|
66
|
-
When you use Webpacker for your CSS, you should move these added stylesheets to the proper location (propably somewhere in `app/javascript` and import them in `application.scss` (or alike) located there.
|
67
|
-
|
68
67
|
## Usage
|
69
68
|
|
70
|
-
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.
|
71
70
|
|
72
|
-
|
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:
|
73
72
|
|
74
73
|
```erb
|
75
|
-
<%=
|
74
|
+
<%= bs5_expandable_list_group do |c| %>
|
76
75
|
<% @posts.each do |post| %>
|
77
76
|
<% c.item do |i| %>
|
78
77
|
<%= i.title { post.title } %>
|
@@ -127,11 +126,11 @@ To show one set:
|
|
127
126
|
...
|
128
127
|
<% c.item do |i| %>
|
129
128
|
<%= i.title do |t| %>
|
130
|
-
|
129
|
+
...
|
131
130
|
<% end %>
|
132
131
|
<% i.actions do %>
|
133
132
|
<%= link_to 'Delete', post, method: :delete, class: 'btn btn-sm btn-outline-danger' %>
|
134
|
-
|
133
|
+
<%= link_to 'Edit', edit_post_path(post), class: 'btn btn-sm btn-outline-secondary' %>
|
135
134
|
<% end %>
|
136
135
|
<%= i.body { ... } %>
|
137
136
|
<% end %>
|
@@ -143,14 +142,14 @@ To show a different set on hovering:
|
|
143
142
|
...
|
144
143
|
<% c.item do |i| %>
|
145
144
|
<%= i.title do |t| %>
|
146
|
-
|
145
|
+
...
|
147
146
|
<% end %>
|
148
147
|
<% i.actions do |a| %>
|
149
|
-
<% a.collapsed %>
|
148
|
+
<% a.collapsed do %>
|
150
149
|
<%= link_to 'Delete', post, method: :delete, class: 'btn btn-sm btn-outline-danger' %>
|
151
150
|
<%= link_to 'Edit', edit_post_path(post), class: 'btn btn-sm btn-outline-secondary' %>
|
152
151
|
<% end %>
|
153
|
-
<% a.expanded %>
|
152
|
+
<% a.expanded do %>
|
154
153
|
<%= link_to 'Details', post_path(post), class: 'btn btn-sm btn-outline-secondary' %>
|
155
154
|
<%= link_to 'Comment' ... %>
|
156
155
|
<%= link_to 'Delete', post, method: :delete, class: 'btn btn-sm btn-outline-danger' %>
|
@@ -161,26 +160,131 @@ To show a different set on hovering:
|
|
161
160
|
<% end %>
|
162
161
|
```
|
163
162
|
|
164
|
-
|
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
|
182
|
+
|
183
|
+
Instead of using the `item`'s methods `title`, `body` and/or `actions` you can just use (HTML-) text as a block.
|
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)):
|
185
|
+
|
186
|
+
```erb
|
187
|
+
<%= bs5_expandable_list_group do |c| %>
|
188
|
+
<% @posts.each do |post| %>
|
189
|
+
<% c.item do |i| %>
|
190
|
+
<%= i.title { post.title } %>
|
191
|
+
<%= i.body { post.text } %>
|
192
|
+
<% end %>
|
193
|
+
<% end %>
|
194
|
+
<% if @posts.next_page %>
|
195
|
+
<% c.item do %>
|
196
|
+
<%= link_to_next_page @posts "Load more" %>
|
197
|
+
<% end %>
|
198
|
+
<% end %>
|
199
|
+
<% end %>
|
200
|
+
```
|
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
|
165
215
|
|
166
|
-
|
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`:
|
167
234
|
|
168
235
|
| name | default | description |
|
169
236
|
|---|---|---|
|
170
|
-
|
|
171
|
-
| `
|
172
|
-
| `
|
173
|
-
|
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
|
+
|
174
241
|
|
242
|
+
### Wrap an item in an extra element
|
243
|
+
|
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.
|
245
|
+
However, you can wrap a list item in a extra element by passing a `wrapper_html` option to the `item` method:
|
246
|
+
|
247
|
+
```erb
|
248
|
+
...
|
249
|
+
<% c.item(wrapper_html: { tag: :turbo_frame, id: dom_id(post) }) do |i| %>
|
250
|
+
<%= i.title do |t| %>
|
251
|
+
<%= t.collapsed { 'Collapsed title' } %>
|
252
|
+
<%= t.expanded { 'Expanded title' } %>
|
253
|
+
<% end %>
|
254
|
+
<%= i.body { ... } %>
|
255
|
+
<% end %>
|
256
|
+
```
|
257
|
+
|
258
|
+
All options passed to the item method are used as HTML attributes of the wrapper, expect for the following:
|
259
|
+
|
260
|
+
| name | default | description |
|
261
|
+
|---|---|---|
|
262
|
+
| `tag` | `:div` | A symbol or string of a valid HTML tag that is used for the tag of the wrapper |
|
263
|
+
|
264
|
+
### Passing options
|
265
|
+
|
266
|
+
The following options can be passed to `bs5_expandable_list_group`:
|
267
|
+
|
268
|
+
| name | default | description |
|
269
|
+
|---|---|---|
|
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. |
|
175
276
|
|
176
277
|
Example:
|
177
278
|
|
178
279
|
```erb
|
179
|
-
<%=
|
280
|
+
<%= bs5_expandable_list_group(accordion: true, stretchable: true) do |c| %>
|
180
281
|
...
|
181
282
|
<% end %>
|
182
283
|
```
|
183
284
|
|
285
|
+
Other options are used as HTML attributes of the list group element.
|
286
|
+
|
287
|
+
|
184
288
|
## Running tests
|
185
289
|
|
186
290
|
```bash
|
@@ -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
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Bs5ExpandableListGroup
|
2
|
+
module ViewComponentsHelper
|
3
|
+
def bs5_expandable_list_group(*args)
|
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|
|
11
|
+
yield c if block_given?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -2,6 +2,11 @@ module Bs5ExpandableListGroup
|
|
2
2
|
class Engine < ::Rails::Engine
|
3
3
|
isolate_namespace Bs5ExpandableListGroup
|
4
4
|
|
5
|
+
# We don't want the developer to add the helper so we 'automate' this:
|
6
|
+
config.to_prepare do
|
7
|
+
ActionController::Base.helper(ViewComponentsHelper)
|
8
|
+
end
|
9
|
+
|
5
10
|
config.generators do |g|
|
6
11
|
g.test_framework :rspec
|
7
12
|
g.assets false
|
@@ -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
|
@@ -86,7 +86,9 @@ dependencies:
|
|
86
86
|
- - ">="
|
87
87
|
- !ruby/object:Gem::Version
|
88
88
|
version: '0'
|
89
|
-
description:
|
89
|
+
description: Bootstrap 5 expandable list group is a Ruby on Rails engine and gives
|
90
|
+
you a simple API for creating expandable and stretchable list groups. A bit like
|
91
|
+
Bootstrap 5's Accordion, Collapse and List group components combined.
|
90
92
|
email:
|
91
93
|
- patrick.baselier@gmail.com
|
92
94
|
executables: []
|
@@ -98,16 +100,17 @@ files:
|
|
98
100
|
- Rakefile
|
99
101
|
- app/assets/config/bs5_expandable_list_group_manifest.js
|
100
102
|
- app/assets/stylesheets/bs5_expandable_list_group/application.css
|
101
|
-
- app/components/bs5/
|
102
|
-
- app/components/bs5/
|
103
|
-
- app/components/bs5/
|
104
|
-
- app/components/bs5/
|
105
|
-
- app/components/bs5/
|
106
|
-
- app/components/bs5/
|
107
|
-
- app/components/bs5/
|
108
|
-
- 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
|
109
111
|
- app/controllers/bs5_expandable_list_group/application_controller.rb
|
110
112
|
- app/helpers/bs5_expandable_list_group/application_helper.rb
|
113
|
+
- app/helpers/bs5_expandable_list_group/view_components_helper.rb
|
111
114
|
- app/jobs/bs5_expandable_list_group/application_job.rb
|
112
115
|
- app/mailers/bs5_expandable_list_group/application_mailer.rb
|
113
116
|
- app/models/bs5_expandable_list_group/application_record.rb
|
@@ -129,7 +132,7 @@ licenses:
|
|
129
132
|
metadata:
|
130
133
|
homepage_uri: https://github.com/bazzel/Bs5ExpandableListGroup
|
131
134
|
source_code_uri: https://github.com/bazzel/Bs5ExpandableListGroup
|
132
|
-
changelog_uri: https://github.com/bazzel/Bs5ExpandableListGroup/CHANGELOG.md
|
135
|
+
changelog_uri: https://github.com/bazzel/Bs5ExpandableListGroup/blob/main/CHANGELOG.md
|
133
136
|
post_install_message:
|
134
137
|
rdoc_options: []
|
135
138
|
require_paths:
|
@@ -148,5 +151,6 @@ requirements: []
|
|
148
151
|
rubygems_version: 3.2.3
|
149
152
|
signing_key:
|
150
153
|
specification_version: 4
|
151
|
-
summary:
|
154
|
+
summary: Rails engine for creating expandable and stretchable list groups with Bootstrap
|
155
|
+
5
|
152
156
|
test_files: []
|
@@ -1,33 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Bs5
|
4
|
-
class ExpandableListGroupComponent < ViewComponent::Base
|
5
|
-
renders_many :items, lambda {
|
6
|
-
ExpandableListItemComponent.new(parent_id: accordion? && id, stretchable: stretchable?)
|
7
|
-
}
|
8
|
-
|
9
|
-
attr_reader :accordion, :stretchable
|
10
|
-
|
11
|
-
def initialize(options = {})
|
12
|
-
@accordion = options.delete(:accordion)
|
13
|
-
@stretchable = options.delete(:stretchable)
|
14
|
-
@id = options[:id]
|
15
|
-
@options = options
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def id
|
21
|
-
@id || "list-group-#{object_id}"
|
22
|
-
end
|
23
|
-
|
24
|
-
def component_class
|
25
|
-
class_names = ['list-group']
|
26
|
-
class_names << @options[:class]
|
27
|
-
class_names
|
28
|
-
end
|
29
|
-
|
30
|
-
alias accordion? accordion
|
31
|
-
alias stretchable? stretchable
|
32
|
-
end
|
33
|
-
end
|
@@ -1,9 +0,0 @@
|
|
1
|
-
<%= tag.div(class: "list-group-item expandable-item", data: component_data_options) do %>
|
2
|
-
<div class="expandable-item-header">
|
3
|
-
<%= title %>
|
4
|
-
<%= actions %>
|
5
|
-
</div>
|
6
|
-
<%= tag.div(id: target_id, class: "expandable-item-body collapse", data: body_data_options) do %>
|
7
|
-
<%= body %>
|
8
|
-
<% end %>
|
9
|
-
<% end %>
|
@@ -1,52 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Bs5
|
4
|
-
class ExpandableListItemComponent < ViewComponent::Base
|
5
|
-
renders_one :title, lambda {
|
6
|
-
ExpandableListItemHeaderTitleComponent.new(target_id: target_id)
|
7
|
-
}
|
8
|
-
renders_one :actions, ExpandableListItemHeaderActionsComponent
|
9
|
-
renders_one :body
|
10
|
-
|
11
|
-
attr_reader :parent_id, :stretchable
|
12
|
-
|
13
|
-
def initialize(options = {})
|
14
|
-
@parent_id = options.delete(:parent_id)
|
15
|
-
@stretchable = options.delete(:stretchable)
|
16
|
-
@options = options
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
def target_id
|
22
|
-
"expandable-list-item-#{object_id}"
|
23
|
-
end
|
24
|
-
|
25
|
-
def body_data_options
|
26
|
-
{}.tap do |h|
|
27
|
-
h['bs-parent'] = "##{parent_id}" if parent_id
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def component_data_options
|
32
|
-
{}.tap do |h|
|
33
|
-
h.merge!(stimulus_attributes) if stretchable?
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def stimulus_attributes
|
38
|
-
{
|
39
|
-
controller: stimulus_controller,
|
40
|
-
"#{stimulus_controller}-target": 'container',
|
41
|
-
"#{stimulus_controller}-item-class": 'stretchable-item',
|
42
|
-
"#{stimulus_controller}-stretched-class": 'stretched'
|
43
|
-
}
|
44
|
-
end
|
45
|
-
|
46
|
-
def stimulus_controller
|
47
|
-
'stretchable-item'
|
48
|
-
end
|
49
|
-
|
50
|
-
alias stretchable? stretchable
|
51
|
-
end
|
52
|
-
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
|