Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(b-collapse): add new prop appear to animate an initially visible collapse #4317

Merged
merged 41 commits into from Nov 15, 2019
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
75801c1
feat(collapse): add new prop `appear` to animate initially visible co…
tmorehouse Oct 30, 2019
0ac5707
Update package.json
tmorehouse Oct 30, 2019
9409fd7
Update README.md
tmorehouse Oct 30, 2019
d5be5a9
Create bv-collapse helper transition component
tmorehouse Oct 30, 2019
700225a
Update bv-collapse.js
tmorehouse Oct 30, 2019
ee3c1e8
Update bv-collapse.js
tmorehouse Oct 30, 2019
dea5656
Update collapse.js
tmorehouse Oct 30, 2019
67d7fcf
Update collapse.js
tmorehouse Oct 30, 2019
96068f7
Update bv-collapse.js
tmorehouse Oct 30, 2019
5884c3f
Update bv-collapse.js
tmorehouse Oct 30, 2019
1358ec4
Update bv-collapse.js
tmorehouse Oct 30, 2019
8ec0eb8
Update bv-collapse.js
tmorehouse Oct 30, 2019
045f7e3
Update bv-collapse.js
tmorehouse Oct 30, 2019
a8d7b1c
Update bv-collapse.js
tmorehouse Oct 30, 2019
207a357
Update bv-collapse.js
tmorehouse Oct 30, 2019
02c5c02
Update collapse.js
tmorehouse Oct 30, 2019
dedf78b
Update collapse.js
tmorehouse Oct 30, 2019
62ba369
Update bv-collapse.js
tmorehouse Oct 30, 2019
5c073fb
Update bv-collapse.js
tmorehouse Oct 30, 2019
1a3555a
Update bv-collapse.js
tmorehouse Oct 30, 2019
f1f0121
Update bv-collapse.js
tmorehouse Oct 30, 2019
474a276
Update bv-collapse.js
tmorehouse Oct 30, 2019
8996928
Update bv-collapse.js
tmorehouse Oct 30, 2019
3dedb9f
Update bv-collapse.js
tmorehouse Oct 30, 2019
578eefd
Update bv-collapse.js
tmorehouse Oct 30, 2019
9a1592f
Merge branch 'dev' into feat/collapse-appear
jacobmllr95 Nov 11, 2019
bb219d2
Merge branch 'dev' into feat/collapse-appear
jacobmllr95 Nov 13, 2019
6dc407e
Update README.md
jacobmllr95 Nov 13, 2019
43cbcfb
Update collapse.js
jacobmllr95 Nov 13, 2019
64c65a8
Update package.json
jacobmllr95 Nov 13, 2019
e023d56
Update bv-collapse.js
jacobmllr95 Nov 13, 2019
0e28d26
Update bv-collapse.js
jacobmllr95 Nov 13, 2019
4ef6513
Merge branch 'dev' into feat/collapse-appear
tmorehouse Nov 13, 2019
4c58fdc
Update bv-collapse.js
tmorehouse Nov 13, 2019
8c127b1
Update bv-collapse.js
tmorehouse Nov 13, 2019
f43831b
Update bv-collapse.js
tmorehouse Nov 13, 2019
a7a8a93
Update bv-collapse.js
tmorehouse Nov 13, 2019
8b0c148
Update bv-collapse.js
tmorehouse Nov 13, 2019
626aa5a
Update bv-collapse.js
tmorehouse Nov 13, 2019
adfbcbb
Merge branch 'dev' into feat/collapse-appear
jacobmllr95 Nov 14, 2019
e3955ac
Merge branch 'dev' into feat/collapse-appear
jacobmllr95 Nov 15, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/components/collapse/README.md
Expand Up @@ -56,6 +56,10 @@ To make the `<b-collapse>` show initially, set the `visible` prop:
<!-- b-collapse-visible.vue -->
```

By default, an initially visible collapse will not animate on mount. To enable the collapse
expanding animation on mount (when `visible` or `v-model` is `true`), set the `appear` prop on
`<b-collapse>`.

## `v-model` support

The component's collapsed (visible) state can also be set with `v-model` which binds internally to
Expand Down
43 changes: 16 additions & 27 deletions src/components/collapse/collapse.js
Expand Up @@ -3,15 +3,14 @@ import idMixin from '../../mixins/id'
import listenOnRootMixin from '../../mixins/listen-on-root'
import normalizeSlotMixin from '../../mixins/normalize-slot'
import { isBrowser } from '../../utils/env'
import { BVCollapse } from '../../utils/bv-collapse'
import {
addClass,
hasClass,
removeClass,
closest,
matches,
reflow,
getCS,
getBCR,
eventOn,
eventOff
} from '../../utils/dom'
Expand Down Expand Up @@ -54,6 +53,11 @@ export const BCollapse = /*#__PURE__*/ Vue.extend({
tag: {
type: String,
default: 'div'
},
appear: {
// If `true` (and `visible` is `true` on mount), animate initially visible
type: Boolean,
default: false
}
},
data() {
Expand Down Expand Up @@ -141,36 +145,26 @@ export const BCollapse = /*#__PURE__*/ Vue.extend({
this.show = !this.show
},
onEnter(el) {
el.style.height = 0
reflow(el)
el.style.height = el.scrollHeight + 'px'
this.transitioning = true
// This should be moved out so we can add cancellable events
this.$emit('show')
},
onAfterEnter(el) {
el.style.height = null
this.transitioning = false
this.$emit('shown')
},
onLeave(el) {
el.style.height = 'auto'
el.style.display = 'block'
el.style.height = getBCR(el).height + 'px'
reflow(el)
this.transitioning = true
el.style.height = 0
// This should be moved out so we can add cancellable events
this.$emit('hide')
},
onAfterLeave(el) {
el.style.height = null
this.transitioning = false
this.$emit('hidden')
},
emitState() {
this.$emit('input', this.show)
// Let v-b-toggle know the state of this collapse
// Let `v-b-toggle` know the state of this collapse
this.$root.$emit(EVENT_STATE, this.safeId(), this.show)
if (this.accordion && this.show) {
// Tell the other collapses in this accordion to close
Expand All @@ -184,13 +178,15 @@ export const BCollapse = /*#__PURE__*/ Vue.extend({
this.$root.$emit(EVENT_STATE_SYNC, this.safeId(), this.show)
},
checkDisplayBlock() {
// Check to see if the collapse has `display: block !important;` set.
// We can't set `display: none;` directly on this.$el, as it would
// trigger a new transition to start (or cancel a current one).
// Check to see if the collapse has `display: block !important` set
// We can't set `display: none` directly on `this.$el`, as it would
// trigger a new transition to start (or cancel a current one)
const restore = hasClass(this.$el, 'show')
removeClass(this.$el, 'show')
const isBlock = getCS(this.$el).display === 'block'
restore && addClass(this.$el, 'show')
if (restore) {
addClass(this.$el, 'show')
}
return isBlock
},
clickHandler(evt) {
Expand All @@ -202,7 +198,7 @@ export const BCollapse = /*#__PURE__*/ Vue.extend({
}
if (matches(el, '.nav-link,.dropdown-item') || closest('.nav-link,.dropdown-item', el)) {
if (!this.checkDisplayBlock()) {
// Only close the collapse if it is not forced to be 'display: block !important;'
// Only close the collapse if it is not forced to be `display: block !important`
this.show = false
}
}
Expand Down Expand Up @@ -246,16 +242,9 @@ export const BCollapse = /*#__PURE__*/ Vue.extend({
[this.normalizeSlot('default')]
)
return h(
'transition',
BVCollapse,
{
props: {
enterClass: '',
enterActiveClass: 'collapsing',
enterToClass: '',
leaveClass: '',
leaveActiveClass: 'collapsing',
leaveToClass: ''
},
props: { appear: this.appear },
on: {
enter: this.onEnter,
afterEnter: this.onAfterEnter,
Expand Down
5 changes: 5 additions & 0 deletions src/components/collapse/package.json
Expand Up @@ -33,6 +33,11 @@
{
"prop": "visible",
"description": "When 'true', expands the collapse"
},
{
"prop": "appear",
"version": "2.2.0",
"description": "When set, and prop 'visible' is true on mount, will animate on initial mount"
}
],
"events": [
Expand Down
79 changes: 79 additions & 0 deletions src/utils/bv-collapse.js
@@ -0,0 +1,79 @@
// Generic collapse transion helper component
//
// Note:
// Applies the classes `collapse`, `show` and `collapsing`
// during the enter/leave transition phases only
// Although it appears that Vue may be leaving the classes
// in-place after the transition completes
import Vue from './vue'
import { mergeData } from 'vue-functional-data-merge'
import { getBCR, reflow, requestAF } from './dom'

// Transition event handler helpers
const onEnter = el => {
el.style.height = 0
// Animaton frame delay neeeded for `appear` to work
requestAF(() => {
reflow(el)
el.style.height = `${el.scrollHeight}px`
})
}

const onAfterEnter = el => {
el.style.height = null
}

const onLeave = el => {
el.style.height = 'auto'
el.style.display = 'block'
el.style.height = `${getBCR(el).height}px`
reflow(el)
el.style.height = 0
}

const onAfterLeave = el => {
el.style.height = null
}

// Default transition props
// `appear` will use the enter classes
const TRANSITION_PROPS = {
css: true,
enterClass: '',
enterActiveClass: 'collapsing',
enterToClass: 'collapse show',
leaveClass: 'collapse show',
leaveActiveClass: 'collapsing',
leaveToClass: 'collapse'
}

// Default transition handlers
// `appear` will use the enter handlers
const TRANSITION_HANDLERS = {
enter: onEnter,
afterEnter: onAfterEnter,
leave: onLeave,
afterLeave: onAfterLeave
}

// @vue/component
export const BVCollapse = /*#__PURE__*/ Vue.extend({
name: 'BVCollapse',
functional: true,
props: {
appear: {
// If `true` (and `visible` is `true` on mount), animate initially visible
type: Boolean,
default: false
}
},
render(h, { props, data, children }) {
return h(
'transition',
// We merge in the `appear` prop last
mergeData(data, { props: TRANSITION_PROPS, on: TRANSITION_HANDLERS }, { props }),
// Note: `<tranition>` supports a single root element only
children
)
}
})