Skip to content
Permalink
Browse files

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
  • Loading branch information
tmorehouse authored and jackmu95 committed Nov 20, 2019
1 parent c71352d commit 8e95bacf9d00562f2676689d067ae0db009cbbb6
@@ -261,6 +261,17 @@ To toggle (open/close) a **specific collapse**, pass the collapse `id`:
this.$root.$emit('bv::toggle::collapse', 'my-collapse-id')
```

## Optionally scoped default slot

<span class="badge badge-info small">New in v2.2.0</span>

The default slot can be optionally scoped. The following scope properties are available:

| Property | Type | Description |
| ---------- | -------- | ------------------------------------ |
| `visible` | Boolean | Visible state of the collapse |
| `close` | Function | When called, will close the collapse |

## Accessibility

The `v-b-toggle` directive will automatically add the ARIA attributes `aria-controls` and
@@ -231,6 +231,10 @@ export const BCollapse = /*#__PURE__*/ Vue.extend({
}
},
render(h) {
const scope = {
visible: this.show,
close: () => (this.show = false)
}
const content = h(
this.tag,
{
@@ -239,7 +243,7 @@ export const BCollapse = /*#__PURE__*/ Vue.extend({
attrs: { id: this.safeId() },
on: { click: this.clickHandler }
},
[this.normalizeSlot('default')]
[this.normalizeSlot('default', scope)]
)
return h(
BVCollapse,
@@ -566,4 +566,59 @@ describe('collapse', () => {

wrapper.destroy()
})

it('default slot scope works', async () => {
let scope = null
const wrapper = mount(BCollapse, {
attachToDocument: true,
propsData: {
// 'id' is a required prop
id: 'test',
visible: true
},
scopedSlots: {
default(props) {
scope = props
return this.$createElement('div', 'foobar')
}
},
stubs: {
// Disable use of default test transitionStub component
transition: false
}
})
const rootWrapper = createWrapper(wrapper.vm.$root)
await waitNT(wrapper.vm)
await waitRAF()
expect(wrapper.element.style.display).toEqual('')
expect(wrapper.emitted('show')).not.toBeDefined() // Does not emit show when initially visible
expect(wrapper.emitted('input')).toBeDefined()
expect(wrapper.emitted('input').length).toBe(1)
expect(wrapper.emitted('input')[0][0]).toBe(true)
expect(rootWrapper.emitted(EVENT_ACCORDION)).not.toBeDefined()
expect(rootWrapper.emitted(EVENT_STATE)).toBeDefined()
expect(rootWrapper.emitted(EVENT_STATE).length).toBe(1)
expect(rootWrapper.emitted(EVENT_STATE)[0][0]).toBe('test') // ID
expect(rootWrapper.emitted(EVENT_STATE)[0][1]).toBe(true) // Visible state
expect(rootWrapper.emitted(EVENT_STATE_SYNC)).not.toBeDefined()

expect(scope).not.toBe(null)
expect(scope.visible).toBe(true)
expect(typeof scope.close).toBe('function')

scope.close()
await waitNT(wrapper.vm)
await waitRAF()

expect(rootWrapper.emitted(EVENT_STATE_SYNC)).toBeDefined()
expect(rootWrapper.emitted(EVENT_STATE_SYNC).length).toBe(2)
expect(rootWrapper.emitted(EVENT_STATE_SYNC)[1][0]).toBe('test') // ID
expect(rootWrapper.emitted(EVENT_STATE_SYNC)[1][1]).toBe(false) // Visible state

expect(scope).not.toBe(null)
expect(scope.visible).toBe(false)
expect(typeof scope.close).toBe('function')

wrapper.destroy()
})
})
@@ -40,6 +40,24 @@
"description": "When set, and prop 'visible' is true on mount, will animate on initial mount"
}
],
"slots": [
{
"name": "default",
"version": "2.2.0",
"scope": [
{
"prop": "visible",
"type": "Boolean",
"description": "Visible state of the collapse: true if the collapse is visible"
},
{
"prop": "close",
"type": "Function",
"description": "Method for closing the collapse"
}
]
}
],
"events": [
{
"event": "input",

0 comments on commit 8e95bac

Please sign in to comment.
You can’t perform that action at this time.