Skip to content

Commit

Permalink
feat(transition): add transition
Browse files Browse the repository at this point in the history
  • Loading branch information
estevanmaito committed Jun 25, 2020
1 parent 6a7a333 commit 46a7d6b
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 4 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,13 @@ plugins: [windmillPlugin()]
### Components

- [x] Button
- [ ] Card
- [x] Card
- [ ] Dropdown
- [ ] Form
- [x] Form
- [ ] Modal
- [ ] Table
- [ ] Avatar
- [ ] Transition
- [x] Transition
- [ ] Backdrop
- [ ] Badge

Expand Down
38 changes: 38 additions & 0 deletions __tests__/Transition.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react'
import { mount } from 'enzyme'
import Transition from '../src/Transition'

describe('Transition', () => {
it('should render without crashing', () => {
mount(
<Transition
show={true}
enter="transform"
enterFrom="opacity-0 -translate-x-1"
enterTo="opacity-100 translate-x-1/2"
leave="transform"
leaveFrom="opacity-100 translate-x-1/2"
leaveTo="opacity-0 -translate-x-1"
>
<span>Hi</span>
</Transition>
)
})

it('should render nested transitions', () => {
mount(
<Transition show={true}>
<Transition
enter="opacity-0"
enterFrom="opacity-0"
enterTo="opacity-0"
leave="opacity-0"
leaveFrom="opacity-0"
leaveTo="opacity-0"
>
<span>Hi</span>
</Transition>
</Transition>
)
})
})
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module.exports = {
collectCoverageFrom: ['src/**/*.js'],
collectCoverageFrom: ['src/**/*.js', '!src/Transition.js'],
setupFilesAfterEnv: ['./setupTests.js'],
coverageThreshold: {
global: {
Expand Down
129 changes: 129 additions & 0 deletions src/Transition.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/**
* https://gist.github.com/adamwathan/e0a791aa0419098a7ece70028b2e641e
*/
import React, { useRef, useEffect, useContext } from 'react'

import { CSSTransition as ReactCSSTransition } from 'react-transition-group'

import PropTypes from 'prop-types'

const TransitionContext = React.createContext({
parent: {},
})

function useIsInitialRender() {
const isInitialRender = useRef(true)
useEffect(() => {
isInitialRender.current = false
}, [])
return isInitialRender.current
}

function CSSTransition({
show,
enter = '',
enterFrom = '',
enterTo = '',
leave = '',
leaveFrom = '',
leaveTo = '',
appear,
children,
}) {
const enterClasses = enter.split(' ').filter((s) => s.length)
const enterFromClasses = enterFrom.split(' ').filter((s) => s.length)
const enterToClasses = enterTo.split(' ').filter((s) => s.length)
const leaveClasses = leave.split(' ').filter((s) => s.length)
const leaveFromClasses = leaveFrom.split(' ').filter((s) => s.length)
const leaveToClasses = leaveTo.split(' ').filter((s) => s.length)

function addClasses(node, classes) {
classes.length && node.classList.add(...classes)
}

function removeClasses(node, classes) {
classes.length && node.classList.remove(...classes)
}

return (
<ReactCSSTransition
appear={appear}
unmountOnExit
in={show}
addEndListener={(node, done) => {
node.addEventListener('transitionend', done, false)
}}
onEnter={(node) => {
addClasses(node, [...enterClasses, ...enterFromClasses])
}}
onEntering={(node) => {
removeClasses(node, enterFromClasses)
addClasses(node, enterToClasses)
}}
onEntered={(node) => {
removeClasses(node, [...enterToClasses, ...enterClasses])
}}
onExit={(node) => {
addClasses(node, [...leaveClasses, ...leaveFromClasses])
}}
onExiting={(node) => {
removeClasses(node, leaveFromClasses)
addClasses(node, leaveToClasses)
}}
onExited={(node) => {
removeClasses(node, [...leaveToClasses, ...leaveClasses])
}}
>
{children}
</ReactCSSTransition>
)
}

CSSTransition.propTypes = {
show: PropTypes.bool,
enter: PropTypes.string,
enterFrom: PropTypes.string,
enterTo: PropTypes.string,
leave: PropTypes.string,
leaveFrom: PropTypes.string,
leaveTo: PropTypes.string,
appear: PropTypes.any,
children: PropTypes.node,
}

function Transition({ show, appear, ...rest }) {
const { parent } = useContext(TransitionContext)
const isInitialRender = useIsInitialRender()
const isChild = show === undefined

if (isChild) {
return (
<CSSTransition
appear={parent.appear || !parent.isInitialRender}
show={parent.show}
{...rest}
/>
)
}

return (
<TransitionContext.Provider
value={{
parent: {
show,
isInitialRender,
appear,
},
}}
>
<CSSTransition appear={appear} show={show} {...rest} />
</TransitionContext.Provider>
)
}

Transition.propTypes = {
show: PropTypes.bool,
appear: PropTypes.any,
}

export default Transition
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export { default as Input } from './Input'
export { default as Label } from './Label'
export { default as Select } from './Select'
export { default as Textarea } from './Textarea'
export { default as Transition } from './Transition'

0 comments on commit 46a7d6b

Please sign in to comment.