Skip to content

Commit 683d618

Browse files
committed
feat(CCollapse): add horizontal variant
1 parent 8c27214 commit 683d618

File tree

4 files changed

+95
-25
lines changed

4 files changed

+95
-25
lines changed

packages/coreui-vue/src/components/collapse/CCollapse.ts

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
1-
import { defineComponent, h, Transition, withDirectives, vShow, RendererElement } from 'vue'
1+
import { defineComponent, h, Transition, ref, RendererElement, withDirectives } from 'vue'
2+
import { vVisible } from '../../directives/v-c-visible'
23

34
const CCollapse = defineComponent({
45
name: 'CCollapse',
56
props: {
7+
/**
8+
* Set horizontal collapsing to transition the width instead of height.
9+
*/
10+
horizontal: {
11+
type: Boolean,
12+
required: false,
13+
},
614
/**
715
* Toggle the visibility of component.
816
*/
@@ -22,46 +30,68 @@ const CCollapse = defineComponent({
2230
'show',
2331
],
2432
setup(props, { slots, emit }) {
25-
const handleBeforeEnter = (el: RendererElement) => {
26-
el.classList.remove('collapse')
27-
el.classList.add('collapsing')
33+
const collapsing = ref(false)
34+
const show = ref(props.visible)
35+
36+
const handleBeforeEnter = () => {
37+
collapsing.value = true
2838
}
39+
2940
const handleEnter = (el: RendererElement, done: () => void) => {
3041
emit('show')
3142
el.addEventListener('transitionend', () => {
32-
el.classList.add('collapse', 'show')
3343
done()
3444
})
35-
el.style.height = `${el.scrollHeight}px`
45+
setTimeout(() => {
46+
if (props.horizontal) {
47+
el.style.width = `${el.scrollWidth}px`
48+
return
49+
}
50+
el.style.height = `${el.scrollHeight}px`
51+
}, 1)
3652
}
53+
3754
const handleAfterEnter = (el: RendererElement) => {
38-
el.classList.remove('collapsing')
39-
el.style.removeProperty('height')
55+
show.value = true
56+
collapsing.value = false
57+
props.horizontal ? el.style.removeProperty('width') : el.style.removeProperty('height')
4058
}
59+
4160
const handleBeforeLeave = (el: RendererElement) => {
42-
el.classList.add('show')
61+
collapsing.value = true
62+
show.value = false
63+
if (props.horizontal) {
64+
el.style.width = `${el.scrollWidth}px`
65+
return
66+
}
4367
el.style.height = `${el.scrollHeight}px`
4468
}
69+
4570
const handleLeave = (el: RendererElement, done: () => void) => {
4671
emit('hide')
47-
el.classList.remove('collapse', 'show')
48-
el.classList.add('collapsing')
4972
el.addEventListener('transitionend', () => {
5073
done()
5174
})
52-
el.style.height = '0px'
75+
setTimeout(() => {
76+
if (props.horizontal) {
77+
el.style.width = '0px'
78+
return
79+
}
80+
el.style.height = '0px'
81+
}, 1)
5382
}
83+
5484
const handleAfterLeave = (el: RendererElement) => {
55-
el.classList.remove('collapsing')
56-
el.classList.add('collapse')
85+
collapsing.value = false
86+
props.horizontal ? el.style.removeProperty('width') : el.style.removeProperty('height')
5787
}
5888

5989
return () =>
6090
h(
6191
Transition,
6292
{
63-
name: 'fade',
64-
onBeforeEnter: (el) => handleBeforeEnter(el),
93+
css: false,
94+
onBeforeEnter: () => handleBeforeEnter(),
6595
onEnter: (el, done) => handleEnter(el, done),
6696
onAfterEnter: (el) => handleAfterEnter(el),
6797
onBeforeLeave: (el) => handleBeforeLeave(el),
@@ -74,15 +104,13 @@ const CCollapse = defineComponent({
74104
'div',
75105
{
76106
class: [
77-
'collapse',
78-
{
79-
show: props.visible,
80-
},
107+
collapsing.value ? 'collapsing' : 'collapse',
108+
{ 'collapse-horizontal': props.horizontal, show: show.value },
81109
],
82110
},
83111
slots.default && slots.default(),
84112
),
85-
[[vShow, props.visible]],
113+
[[vVisible, props.visible]],
86114
),
87115
)
88116
},

packages/coreui-vue/src/components/collapse/__test__/__snapshots__/CCollapse.spec.ts.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
exports[`Loads and display CCollapse component renders correctly 1`] = `
44
"<transition-stub>
5-
<div class=\\"collapse\\" style=\\"display: none;\\">Default slot</div>
5+
<div class=\\"collapse\\">Default slot</div>
66
</transition-stub>"
77
`;
88

packages/docs/api/collapse/CCollapse.api.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ import CCollapse from '@coreui/vue/src/components/collapse/CCollapse'
88

99
#### Props
1010

11-
| Prop name | Description | Type | Values | Default |
12-
| ----------- | ----------------------------------- | ------- | ------ | ------- |
13-
| **visible** | Toggle the visibility of component. | boolean | - | |
11+
| Prop name | Description | Type | Values | Default |
12+
| -------------- | -------------------------------------------------------------------- | ------- | ------ | ------- |
13+
| **horizontal** | Set horizontal collapsing to transition the width instead of height. | boolean | - | |
14+
| **visible** | Toggle the visibility of component. | boolean | - | |
1415

1516
#### Events
1617

packages/docs/components/collapse.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,46 @@ You can use a link or a button component.
5252
</script>
5353
```
5454

55+
## Horizontal
56+
57+
The collapse plugin also supports horizontal collapsing. Add the `horizontal` property to transition the `width` instead of `height` and set a `width` on the immediate child element.
58+
59+
:::demo
60+
<CButton class="mb-3" color="primary" aria-expanded={visible} aria-controls="collapseWidthExample" @click="visibleHorizontal = !visibleHorizontal">Button</CButton>
61+
<div style="min-height: 120px">
62+
<CCollapse horizontal :visible="visibleHorizontal">
63+
<CCard style="width: 300px">
64+
<CCardBody>
65+
This is some placeholder content for a horizontal collapse. It's hidden by default and shown when triggered.
66+
</CCardBody>
67+
</CCard>
68+
</CCollapse>
69+
</div>
70+
:::
71+
```vue
72+
<template>
73+
<CButton class="mb-3" color="primary" aria-expanded={visible} aria-controls="collapseWidthExample" @click="visibleHorizontal = !visibleHorizontal">Button</CButton>
74+
<div style="min-height: 120px">
75+
<CCollapse horizontal :visible="visibleHorizontal">
76+
<CCard style="width: 300px">
77+
<CCardBody>
78+
This is some placeholder content for a horizontal collapse. It's hidden by default and shown when triggered.
79+
</CCardBody>
80+
</CCard>
81+
</CCollapse>
82+
</div>
83+
</template>
84+
<script>
85+
export default {
86+
data() {
87+
return {
88+
visibleHorizontal: false,
89+
}
90+
}
91+
}
92+
</script>
93+
```
94+
5595
## Multiple targets
5696

5797
A `<CButton>` can show and hide multiple elements.
@@ -144,6 +184,7 @@ A `<CButton>` can show and hide multiple elements.
144184
data() {
145185
return {
146186
visible: false,
187+
visibleHorizontal: false,
147188
visibleA: false,
148189
visibleB: false,
149190
}

0 commit comments

Comments
 (0)