Skip to content

Commit 8e95bac

Browse files
tmorehousejacobmllr95
authored andcommitted
feat(b-collapse): add optional scoping to default slot (#4405)
* feat(b-collapse): add optional scoping to default slot * Update collapse.js * Update collapse.js * Update collapse.js * Update collapse.js * Update package.json * Update collapse.spec.js * Update collapse.spec.js * Update collapse.spec.js * Update README.md * Update collapse.spec.js * Update README.md
1 parent c71352d commit 8e95bac

File tree

4 files changed

+89
-1
lines changed

4 files changed

+89
-1
lines changed

src/components/collapse/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,17 @@ To toggle (open/close) a **specific collapse**, pass the collapse `id`:
261261
this.$root.$emit('bv::toggle::collapse', 'my-collapse-id')
262262
```
263263

264+
## Optionally scoped default slot
265+
266+
<span class="badge badge-info small">New in v2.2.0</span>
267+
268+
The default slot can be optionally scoped. The following scope properties are available:
269+
270+
| Property | Type | Description |
271+
| ---------- | -------- | ------------------------------------ |
272+
| `visible` | Boolean | Visible state of the collapse |
273+
| `close` | Function | When called, will close the collapse |
274+
264275
## Accessibility
265276

266277
The `v-b-toggle` directive will automatically add the ARIA attributes `aria-controls` and

src/components/collapse/collapse.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,10 @@ export const BCollapse = /*#__PURE__*/ Vue.extend({
231231
}
232232
},
233233
render(h) {
234+
const scope = {
235+
visible: this.show,
236+
close: () => (this.show = false)
237+
}
234238
const content = h(
235239
this.tag,
236240
{
@@ -239,7 +243,7 @@ export const BCollapse = /*#__PURE__*/ Vue.extend({
239243
attrs: { id: this.safeId() },
240244
on: { click: this.clickHandler }
241245
},
242-
[this.normalizeSlot('default')]
246+
[this.normalizeSlot('default', scope)]
243247
)
244248
return h(
245249
BVCollapse,

src/components/collapse/collapse.spec.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,4 +566,59 @@ describe('collapse', () => {
566566

567567
wrapper.destroy()
568568
})
569+
570+
it('default slot scope works', async () => {
571+
let scope = null
572+
const wrapper = mount(BCollapse, {
573+
attachToDocument: true,
574+
propsData: {
575+
// 'id' is a required prop
576+
id: 'test',
577+
visible: true
578+
},
579+
scopedSlots: {
580+
default(props) {
581+
scope = props
582+
return this.$createElement('div', 'foobar')
583+
}
584+
},
585+
stubs: {
586+
// Disable use of default test transitionStub component
587+
transition: false
588+
}
589+
})
590+
const rootWrapper = createWrapper(wrapper.vm.$root)
591+
await waitNT(wrapper.vm)
592+
await waitRAF()
593+
expect(wrapper.element.style.display).toEqual('')
594+
expect(wrapper.emitted('show')).not.toBeDefined() // Does not emit show when initially visible
595+
expect(wrapper.emitted('input')).toBeDefined()
596+
expect(wrapper.emitted('input').length).toBe(1)
597+
expect(wrapper.emitted('input')[0][0]).toBe(true)
598+
expect(rootWrapper.emitted(EVENT_ACCORDION)).not.toBeDefined()
599+
expect(rootWrapper.emitted(EVENT_STATE)).toBeDefined()
600+
expect(rootWrapper.emitted(EVENT_STATE).length).toBe(1)
601+
expect(rootWrapper.emitted(EVENT_STATE)[0][0]).toBe('test') // ID
602+
expect(rootWrapper.emitted(EVENT_STATE)[0][1]).toBe(true) // Visible state
603+
expect(rootWrapper.emitted(EVENT_STATE_SYNC)).not.toBeDefined()
604+
605+
expect(scope).not.toBe(null)
606+
expect(scope.visible).toBe(true)
607+
expect(typeof scope.close).toBe('function')
608+
609+
scope.close()
610+
await waitNT(wrapper.vm)
611+
await waitRAF()
612+
613+
expect(rootWrapper.emitted(EVENT_STATE_SYNC)).toBeDefined()
614+
expect(rootWrapper.emitted(EVENT_STATE_SYNC).length).toBe(2)
615+
expect(rootWrapper.emitted(EVENT_STATE_SYNC)[1][0]).toBe('test') // ID
616+
expect(rootWrapper.emitted(EVENT_STATE_SYNC)[1][1]).toBe(false) // Visible state
617+
618+
expect(scope).not.toBe(null)
619+
expect(scope.visible).toBe(false)
620+
expect(typeof scope.close).toBe('function')
621+
622+
wrapper.destroy()
623+
})
569624
})

src/components/collapse/package.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,24 @@
4040
"description": "When set, and prop 'visible' is true on mount, will animate on initial mount"
4141
}
4242
],
43+
"slots": [
44+
{
45+
"name": "default",
46+
"version": "2.2.0",
47+
"scope": [
48+
{
49+
"prop": "visible",
50+
"type": "Boolean",
51+
"description": "Visible state of the collapse: true if the collapse is visible"
52+
},
53+
{
54+
"prop": "close",
55+
"type": "Function",
56+
"description": "Method for closing the collapse"
57+
}
58+
]
59+
}
60+
],
4361
"events": [
4462
{
4563
"event": "input",

0 commit comments

Comments
 (0)