mirror of
https://github.com/Shopify/draggable.git
synced 2026-02-01 16:46:56 +00:00
Basic swap animation plugin
This commit is contained in:
parent
55dd819083
commit
de7a441e47
50
src/Plugins/SwapAnimation/README.md
Normal file
50
src/Plugins/SwapAnimation/README.md
Normal file
@ -0,0 +1,50 @@
|
||||
## SwapAnimation
|
||||
|
||||
The swap animation plugin currently only works with `Sortable`. It adds a swap animation on `sortable:sorted`,
|
||||
and animates both `source` and `over` via `translate3d`. It is currently possible to change the duration and
|
||||
the easing function of the animation.
|
||||
|
||||
This plugin is not included by default, so make sure to import it before using.
|
||||
|
||||
### Import
|
||||
|
||||
```js
|
||||
import {SwapAnimation} from '@shopify/draggable/plugins/swap-animation';
|
||||
```
|
||||
|
||||
```html
|
||||
<script src="https://cdn.jsdelivr.net/npm/@shopify/draggable@1.0.0-beta.3/lib/draggable/plugins/swap-animation"></script>
|
||||
```
|
||||
|
||||
### API
|
||||
|
||||
**`new SwapAnimation(draggable: Draggable): SwapAnimation`**
|
||||
To create a swap animation plugin instance.
|
||||
|
||||
### Options
|
||||
|
||||
**`duration {Integer}`**
|
||||
The duration option allows you to specify the animation during for a single swap. Default: `150`
|
||||
|
||||
**`easingFunction {String}`**
|
||||
The easing option allows you to specify an animation easing function. Default: `'ease-in-out'`
|
||||
|
||||
### Examples
|
||||
|
||||
```js
|
||||
import {Sortable, Plugins} from '@shopify/draggable';
|
||||
|
||||
const sortable = new Sortable(document.querySelectorAll('ul'), {
|
||||
draggable: 'li',
|
||||
swapAnimation: {
|
||||
duration: 200,
|
||||
easingFunction: 'ease-in-out',
|
||||
},
|
||||
plugins: [Plugins.SwapAnimation],
|
||||
});
|
||||
```
|
||||
|
||||
### Known issues
|
||||
|
||||
- Only works with vertical lists
|
||||
- Animations are not staggering yet
|
||||
69
src/Plugins/SwapAnimation/SwapAnimation.js
Normal file
69
src/Plugins/SwapAnimation/SwapAnimation.js
Normal file
@ -0,0 +1,69 @@
|
||||
export const defaultOptions = {
|
||||
duration: 150,
|
||||
easingFunction: 'ease-in-out',
|
||||
};
|
||||
|
||||
export default class SwapAnimation {
|
||||
constructor(draggable) {
|
||||
this.draggable = draggable;
|
||||
|
||||
this.options = {
|
||||
...defaultOptions,
|
||||
...this.getOptions(),
|
||||
};
|
||||
|
||||
this.onSortableSorted = this.onSortableSorted.bind(this);
|
||||
}
|
||||
|
||||
attach() {
|
||||
this.draggable.on('sortable:sorted', this.onSortableSorted);
|
||||
}
|
||||
|
||||
detach() {
|
||||
this.draggable.off('sortable:sorted', this.onSortableSorted);
|
||||
}
|
||||
|
||||
onSortableSorted({oldIndex, newIndex, dragEvent}) {
|
||||
const {source, over} = dragEvent;
|
||||
|
||||
cancelAnimationFrame(this.lastAnimationFrame);
|
||||
|
||||
// Can be done in a separate frame
|
||||
this.lastAnimationFrame = requestAnimationFrame(() => {
|
||||
if (oldIndex >= newIndex) {
|
||||
animate(source, over, this.options);
|
||||
} else {
|
||||
animate(over, source, this.options);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getOptions() {
|
||||
return this.draggable.options.swapAnimation || {};
|
||||
}
|
||||
}
|
||||
|
||||
function animate(top, bottom, {duration, easingFunction}) {
|
||||
const height = top.offsetHeight;
|
||||
|
||||
for (const element of [top, bottom]) {
|
||||
element.style.pointerEvents = 'none';
|
||||
}
|
||||
|
||||
top.style.transform = `translate3d(0, ${height}px, 0)`;
|
||||
bottom.style.transform = `translate3d(0, -${height}px, 0)`;
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
for (const element of [top, bottom]) {
|
||||
element.addEventListener('transitionend', resetElementOnTransitionEnd);
|
||||
element.style.transition = `transform ${duration}ms ${easingFunction}`;
|
||||
element.style.transform = '';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function resetElementOnTransitionEnd(event) {
|
||||
event.target.style.transition = '';
|
||||
event.target.style.pointerEvents = '';
|
||||
event.target.removeEventListener('transitionend', resetElementOnTransitionEnd);
|
||||
}
|
||||
6
src/Plugins/SwapAnimation/index.js
Normal file
6
src/Plugins/SwapAnimation/index.js
Normal file
@ -0,0 +1,6 @@
|
||||
import SwapAnimation, {defaultOptions} from './SwapAnimation';
|
||||
|
||||
export default SwapAnimation;
|
||||
export {
|
||||
defaultOptions as defaultSwapAnimationOptions,
|
||||
};
|
||||
@ -1,7 +1,9 @@
|
||||
import Collidable from './Collidable';
|
||||
import Snappable from './Snappable';
|
||||
import SwapAnimation from './SwapAnimation';
|
||||
|
||||
export {
|
||||
Collidable,
|
||||
Snappable,
|
||||
SwapAnimation,
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user