Transitions manager allows to handle and dispatch transition states from anywhere in the application.
npm i @cher-ami/transitions-manager
TransitionsManager
allows to handle and dispatch two types of states:
- mountState
mount | unmount
- playState
hidden | play-in | visible | play-out
The life cycle of a single transition order could be:
mount
(mountState)play-in
(playState)visible
(playState)play-out
(playState)hidden
(playState) - defaultunmount
(mountState) - default
It's possible to manage a transitions without using the mountState and only working with playState. The mountState is useful specificaly about the React usage.
Create a new instance to manager the transitions of your component:
export const componentTransitionsManager = new TransitionsManager()
Listen mountState
change:
const handleMountState = (mountState) => {
if (mountState === "mount") {
// do somthing and resolve mountState
componentTransitionsManager.mountComplete()
}
if (mountState === "unmount") {
// do somthing and resolve mountState
componentTransitionsManager.unmountComplete()
}
}
// start to listen
componentTransitionsManager.mountStateSignal.on(handleMountState)
// stop...
componentTransitionsManager.mountStateSignal.off(handleMountState)
Listen playState
change on the same way:
const handlePlayState = (playState) => {
if (playState === "play-in") {
// do something and resolve transition state
componentTransitionsManager.playInComplete()
}
if (playState === "play-out") {
// do something and resolve transition state
componentTransitionsManager.playOutComplete()
}
}
// start to listen
componentTransitionsManager.playStateSignal.on(handlePlayState)
// stop...
componentTransitionsManager.playStateSignal.off(handlePlayState)
Now from anywhere, dispatch a new transition state with these methods
componentTransitionsManager.mount()
componentTransitionsManager.playIn()
componentTransitionsManager.playOut()
componentTransitionsManager.unmount()
playIn
and playOut
methods accept options parameters.
componentTransitionsManager.playIn({ duration: 0 })
From the components:
componentTransitionsManager.playStateSignal.on((playState, options) => {
console.log(options) // { duration: 0 }
})
Default options can be set on the manager instance:
const componentTransitionsManager = new TransitionsManager({
options: {
duration: 1
}
})
For typescript developers, GOption generic type is available on instance
const componentTransitionsManager = new TransitionsManager<{duration?: number}>({
options: {
duration: 1
}
})
TransitionsManager
is ready to use with vanilla javascript as above but it has been built for a React usage too. The API comes with hooks!
- Create a new transitionsManager instance as above
- Wrap your component by
TransitionsHoc(component, manager)
- Then, define transitions in
usePlayIn
andusePlayOut
hooks callback.
export const componentTransitionsManager = new TransitionsManager()
function Component() {
usePlayIn(componentTransitionsManager, async (done, options) => {
await myPlayIn()
done()
})
usePlayOut(componentTransitionsManager, async (done, options) => {
await myPlayOut()
done()
})
return <div>...</div>
}
export default TransitionsHoc(Component, componentTransitionsManager)
Now, from anywhere in the application, you can play the component via componentTransitionsManager
his own transitionsManager instance.
await componentTransitionsManager.playIn()
// now, the transtion is done.
componentTransitionsManager.playIn()
will execute the transition function
of usePlayIn
hook defined previously in Component. This method returns a
promise that will be resolved when the transition is done with done()
function
from the same hook. Of course, "awaiting" the promise is not mandatory.
The TransitionsHoc
function will mount and unmount automatically the component
before play out and after play out. It's possible to only play in and play out
without destroy the component with autoMountUnmount
option:
const componentTransitionsManager = new TransitionsManager({ autoMountUnmount: false })
Instead of handle the transitionsManager playState with usePlayIn
and usePlayOut
hooks, you can use the useTransitionsManager
hook in your
component.
This one returns the current playState of the transitionsManager instance when
it changes. In this case, you have to execute the playInComplete
and playOutComplete
functions when the transition is done.
useTransitionsManager(componentTransitionsManager, async (playState, options) => {
if (playState === "play-in") {
await myPlayIn()
componentTransitionsManager.playInComplete()
}
if (playState === "play-out") {
await myPlayOut()
componentTransitionsManager.playOutComplete()
}
})
// or get state from useTransitionsManager hook
const {playState, options} = useTransitionsManager(componentTransitionsManager)
// ...
If TransitionsHoc
wrapper is not used, the mount and unmount component state
can be managed manually. By using useIsMount
hook from the parent component,
you can check the mount and unmount boolean state to condition the rendering.
const App = () => {
const mountComponent = useIsMount(componentTransitionsManager)
return <div>{mountComponent && <Component/>}</div>
}
Now, you can mount and unmount the component.
playIn
method will call mount
methods before is execution, and playOut
will call unmount
methods after is execution automatically.
await componentTransitionsManager.playIn() // auto mount + playIn
// ...
await componentTransitionsManager.playOut() // playOut + auto unmount
If the autoMountUnmount
option is disable, you will have to mount and unmount
manually the component as below:
await componentTransitionsManager.mount()
await componentTransitionsManager.playIn()
// ...
await componentTransitionsManager.playOut()
await componentTransitionsManager.unmount()
@wbe/debug is used on this project. It allows to easily get logs information on development and production modes.
- To use it, add this line in your browser console:
localStorage.debug = "TransitionsManager:*"
- Optionally, pass a name parameter to the instance to print it in the debug namespace.
const componentTransitionsManager = new TransitionsManager({name: "Component"})
{ name?: string, autoMountUnmount?: boolean, options?: Record<any, any> }
name
(optional) used by debug as namespaceautoMountUnmount
(optional) playIn will auto mount, playOut will auto unmount - default is trueoptions
(optional) list of default playIn and playOut options
mount(): Promise<void>
mountComplete(): void
unmount(): Promise<void>
unmountComplete(): void
playIn(options?: Partials<string, any>): Promise<void>
playInComplete(): void
playOut(options?: Partials<string, any>): Promise<void>
playOutComplete(): void
stagger(delay: number = 1, anims: (()=> any)[]): [promise: () => Promise<any>, cancel: () => void]
In some case, you want to execute a list of transitions in a staggered way.
Staggered transition can be setted with the util stagger
function.
import {stagger} from "@cher-ami/transitions-manager"
const [start, clear] = stagger(0.1, [
componentTransitionsManager.playIn,
FooterTransitionsManager.playIn,
])
// start staggered transition
await start()
// clear staggered transition if needed
clear()
pnpm i
Start dev server for specific example
pnpm run dev:basic
Start build:watch on the lib witch is symlinked to the example
pnpm run build:watch
Start unit tests watch during development
pnpm run test:watch