![require(esm) Backported to Node.js 20, Paving the Way for ESM-Only Packages](https://cdn.sanity.io/images/cgdhsj6q/production/be8ab80c8efa5907bc341c6fefe9aa20d239d890-1600x1097.png?w=400&fit=max&auto=format)
Security News
require(esm) Backported to Node.js 20, Paving the Way for ESM-Only Packages
require(esm) backported to Node.js 20, easing the transition to ESM-only packages and reducing complexity for developers as Node 18 nears end-of-life.
@dark-engine/animations
Advanced tools
Spring based animations for Dark
npm:
npm install @dark-engine/animations
yarn:
yarn add @dark-engine/animations
CDN:
<script src="https://unpkg.com/@dark-engine/animations/dist/umd/dark-animations.production.min.js"></script>
import { type SpringValue, Animated, useSpring } from '@dark-engine/animations';
const App = component(() => {
const [isOpen, setIsOpen] = useState(false);
const [spring] = useSpring(
{
from: { opacity: val(isOpen) },
to: { opacity: val(isOpen) },
},
[isOpen],
);
return (
<>
<button onClick={() => setIsOpen(x => !x)}>toggle</button>
<Animated spring={spring} fn={styleFn}>
<div>Hello</div>
</Animated>
</>
);
});
const val = (isOpen: boolean) => isOpen ? 1 : 0;
const styleFn = (e: HTMLElement, x: SpringValue<'opacity'>) => e.style.setProperty('opacity', `${x.opacity}`);
import {
type Spring,
type SpringValue,
Animated,
useSpring,
useSprings,
useTrail,
useTransition,
useChain,
preset,
VERSION,
} from '@dark-engine/animations'
In the library, animations are grounded in the principles of spring physics. To achieve the desired effect, it’s necessary to fine-tune parameters such as mass, tension, and friction. The animation comes to life using an appropriate hook. The transmission of property values is facilitated through a special Animated
component, which serves as a conduit between the hook and the animated element. The entire process unfolds via a subscription, eliminating the need for component rerenders. This approach ensures a seamless and efficient animation experience.
useSpring
The hook that allows you to animate multiple values at once.
const App = component(() => {
const [isOpen, setIsOpen] = useState(false);
const [spring] = useSpring(
{
from: { opacity: val(isOpen), scale: val(isOpen) },
to: { opacity: val(isOpen), scale: val(isOpen) },
config: key => ({ tension: key === 'scale' ? 200 : isOpen ? 100 : 400, precision: 4 }),
},
[isOpen],
);
return (
<>
<button onClick={() => setIsOpen(x => !x)}>toggle</button>
<Animated spring={spring} fn={styleFn}>
<div class='box'>Hello world</div>
</Animated>
</>
);
});
const val = (isOpen: boolean) => (isOpen ? 1 : 0);
const styleFn = (element: HTMLDivElement, value: SpringValue<'opacity' | 'scale'>) => {
element.style.setProperty('opacity', `${value.opacity}`);
element.style.setProperty('transform', `scale(${value.scale}) translate(-50%, -50%)`);
};
What's going on here?
from
and to
parameters, which change depending on the flag in the state.Animated
component is taking a spring object and a function describing how it should change styles during the animation process.from
or to
depending on the flag.https://github.com/atellmer/dark/assets/16635118/42b400a0-fa35-4440-b23b-35d27531591d
useSprings
A generalized version of useSpring
takes as input the number of elements that need to be animated, as well as a function that creates a config depending on the index of the element. Needed for creating complex animations where elements are processed taking into account the position and other parameters of other elements.
const [springs, api] = useSprings(4, idx => createConfig(idx));
...
const handleDragStart = (idx: number) => e => {
...
api.start(createConfig(idx));
};
...
return (
...
<div class='content'>
{springs.map((spring, idx) => {
return (
<Animated spring={spring} fn={styleFn}>
<div class='item' onPointerDown={handleDragStart(idx)}>{idx}</div>
</Animated>
);
})}
</div>
)
https://github.com/atellmer/dark/assets/16635118/453b9249-9667-4e80-b456-a48fdf2a8334
useTrail
The hook is also based on useSprings
, but with minor changes that allow you to apply animations with a slight delay relative to other animated elements. In this case, the delay is not based on timeout, but on events. Can be useful for creating synchronously moving components.
const [size, setSize] = useState(10);
const [springs, api] = useTrail(size, () => ({
from: { x: -100, y: -100 },
config: () => preset('gentle'),
}));
...
return (
...
<>
{springs.map((spring, idx) => {
return (
<Animated spring={spring} fn={styleFn(idx)}>
<Item />
</Animated>
);
})}
</>
);
https://github.com/atellmer/dark/assets/16635118/1342931b-004e-4b7b-9faf-6adf251abc35
useTransition
The hook that animates any manipulations with the tree: adding, moving, replacing and deleting nodes. It works on the basis of an array of data, each element of which has a unique key, which allows you to compare diff elements. Returns a special transition
function within which it manages the keys.
const [items, setItems] = useState(['A']);
const [transition] = useTransition(
items,
x => x,
() => ({
from: { opacity: 0, x: isNext ? 100 : -100 },
enter: { opacity: 1, x: 0 },
leave: { opacity: 0, x: isNext ? -50 : 50 },
}),
);
...
return (
...
<Container>
{transition(({ spring, item }) => {
return (
<Animated spring={spring} fn={styleFn}>
<Item $color={colors[item]}>{item}</Item>
</Animated>
);
})}
</Container>
)
https://github.com/atellmer/dark/assets/16635118/dc1019d2-512d-4d7a-99c0-48c52c08270b
https://github.com/atellmer/dark/assets/16635118/2584d8e0-d44e-4575-9d3d-cc2a62a96692
useChain
Allows you to create chains of heterogeneous animations (springs, trails, transitions), which are launched in a certain sequence. Can be used to create complex animations of the appearance or disappearance of interface elements.
const [spring, springApi] = useSpring(
{
from: { size: 20, green: 105, blue: 180 },
to: { size: isOpen ? 100 : 20, green: isOpen ? 255 : 105, blue: isOpen ? 255 : 180 },
config: () => preset('stiff'),
},
[isOpen],
);
const [transition, transitionApi] = useTransition(
isOpen ? data : [],
x => x.name,
() => ({
from: { opacity: 0, scale: 0 },
enter: { opacity: 1, scale: 1 },
leave: { opacity: 0, scale: 0 },
trail: 400 / data.length,
}),
);
useChain(isOpen ? [springApi, transitionApi] : [transitionApi, springApi], [0, isOpen ? 0.1 : 0.6]);
...
return (
...
<Animated spring={spring} fn={springStyleFn}>
<div class='container' onClick={() => setIsOpen(x => !x)}>
{transition(({ spring, item }) => {
return (
<Animated spring={spring} fn={transitionStyleFn(item)}>
<div class='item' />
</Animated>
);
})}
</div>
</Animated>
);
https://github.com/atellmer/dark/assets/16635118/c1d3e472-dc0b-4861-8b05-3cbf9ef71f2c
MIT © Alex Plex
FAQs
Spring based animations for Dark
The npm package @dark-engine/animations receives a total of 4 weekly downloads. As such, @dark-engine/animations popularity was classified as not popular.
We found that @dark-engine/animations demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
require(esm) backported to Node.js 20, easing the transition to ESM-only packages and reducing complexity for developers as Node 18 nears end-of-life.
Security News
PyPI now supports iOS and Android wheels, making it easier for Python developers to distribute mobile packages.
Security News
Create React App is officially deprecated due to React 19 issues and lack of maintenance—developers should switch to Vite or other modern alternatives.