Сompletely mimics the behavior of a native scroll with mouse drag, index navigation, acceleration, gravity, easings, custom animations & infinite loop mode.
Try the DEMO.
Getting started
The package is available via NPM:
npm i -D @slidy/core or via CDN:
<script src="https://unpkg.com/@slidy/core"></script> Playground is available in svelte REPL.
Usage Examples
There are several options how to get Slidy into your project.
ES Module Import
<head>
<script type="module">
import { slidy } from "https://unpkg.com/@slidy/core/dist/index.mjs";
slidy(document.querySelector("#node"))
</script>
</head>
<section>
<ul id="node">
<!-- slide items -->
</ul>
</section> CommonJS Require
<head>
<script type="module">
import { slidy } from "https://unpkg.com/@slidy/core/dist/index.cjs";
slidy(document.querySelector("#node"))
</script>
</head>
<section>
<ul id="node">
<!-- slidy items -->
</ul>
</section> IIFE as Window Object
<head>
<script src="https://unpkg.com/@slidy/core"></script>
</head>
<script>
let slidy = null;
let node = document.querySelector("#slidy"),
window.onload = () => {
slidy = Slidy.core(node);
}
</script>
<section>
<ul id="slidy">
<!-- slidy items -->
</ul>
</section> SvelteJS
To use slidy with SvelteJS Framework, pass slidy as action into the parent DOM node:
<script>
import { slidy } from "@slidy/core";
</script>
<section>
<ul use:slidy>
<!-- slidy items -->
</ul>
</section>API
slidy have two arguments: required node and optional options.
Options
| Key | Default | Type | Description |
|---|---|---|---|
index | 0 | number | The starting index on render. |
clamp | 0 | number | Defines the step in number of slides to slide on. |
indent | 1 | number | Creates an indent at the edges. The value is calculated from the gap: gap * indent |
sensity | 5 | number | Defines sensite as the pixels required to drag in order to start move, 0 when sliding. |
gravity | 1.2 | number | Controls the gravity value 0 (space) : 1 (earth) : 2 (underground). |
duration | 375 | number | Sliding duration in ms. |
animation | undefined | AnimationFunc | Custom sliding animation. Predefined sets are available via @slidy/animation. |
easing | undefined | (t: number) => number | Sliding easing behaviour. Predefined sets are available vie @slidy/easing. |
snap | undefined | string | Defines an area to “snap” the slide: "start", "center", "end", "deck", undefined. By default the behaviour is clamp sliding by edges. |
axis | undefined | "x" or "y" | Defines the flow direction. |
loop | false | boolean | Activated the infinite sliding mode. |
Readonly properties
| Key | Type | Description |
|---|---|---|
position | number | Current position |
direction | number | Children move direction |
vertical | number | Children axis flow: 0 or any Number as true |
reverse | number | Children reverse flow: -1 or 1 |
Flow
To control the flow direction use one of the options on the parent node:
flex-flow: row-reverse | column-reverseCSS property;direction: rtlCSS property;dir="rtl"HTML attribute.
To use deck flow use the snap: "deck" option, it may be required for some animations.
Usage example
<head>
<script type="module">
import { slidy } from '@slidy/core';;
import { linear } from '@slidy/easing';
import { fade } from '@slidy/animation';
const options = {
index: 0,
clamp: 0,
indent: 1,
sensity: 5,
gravity: 1.2,
duration: 375,
animation: fade,
easing: linear,
snap: 'center',
axis: 'x',
loop: false,
};
const node = document.querySelector("#node");
slidy(node, options);
</script>
</head>
<section>
<ul id="node">
<!-- items -->
</ul>
</section>Events
| Name | Detail | Description |
|---|---|---|
mount | {options} | node.children.length and node.children are connected. |
resize | {ROE} | The target node changed it’s size: ROE: ResizeObserverEntry[] |
move | {index,position} | The sliding occured. |
index | {index} | The index was changed. |
keys | {e.key} | The key is pressed during the target node focus. Arrow keys behaviour is predefined for navigation with preventDefault used on them. To get the focus use tabIndex=0 attribute on the target node. |
update | {updated.options} | Options were changed. |
destroy | {node} | Targed node is unmounted from the DOM or destroy() method was used. |
Events Usage Example
<head>
<script type="module">
import { slidy } from "@slidy/core";
const node = document.querySelector("#node");
slidy(document.querySelector("#node"));
node.addEventListener("mount", e => console.log(e));
node.onupdate = e => console.log(e.detail);
function onMove(e) {
const { index, position } = e.detail
console.log(index, position)
}
</script>
</head>
<section>
<ul id="node" onmove="onMove" tabindex="0">
<!-- items -->
</ul>
</section>Methods
| Name | Description |
|---|---|
to(index: number) | Scrolls to index. |
update({ option: value }) | Update property in options. |
destroy() | Remove event listners, observers and default properties on slidy instance. |
Methods Usage Example
<head>
<script type="module">
import { slidy } from "https://unpkg.com/@slidy/core/dist/index.mjs";
const node = document.querySelector("#node");
const prev = document.querySelector("#prev");
const next = document.querySelector("#next");
slidy(node);
slidy.update({ snap: "center" });
prev.onclick = () => slidy.to(index - 1);
next.onclick = () => slidy.to(index + 1);
</script>
</head>
<section>
<ul id="node">
<!-- items -->
</ul>
</section>
<nav>
<button id="prev">←</button>
<button id="next">→</button>
</nav>
<!--
If `slidy()` is defined in global scope, use global event handlers as attribures:
<nav>
<button onclick="slidy.to(index - 1)">←</button>
<button onclick="slidy.to(index + 1)">→</button>
</nav>
-->Easing
Easing is an animation function, also known as timing function. It allows to create smooth sliding transitions.
/** Both input and output are numbers in range [0, 1].
type Easing = (t: number) => number; By default an easing function is linear. Examples of easing function can be seen here.
The set of predefined easing functions is available as [@slidy/easing][separate package].
Animation
animation function allows to define a custom sliding animation.
interface AnimationArgs {
node: HTMLElement;
child: Child;
options: Options;
translate: string;
}
type AnimationFunc = (args: AnimationArgs) => CSSStyleDeclaration; Functions receives 4 arguments:
| Name | Type | Description |
|---|---|---|
node | HTMLElement | slidy instance root DOM node. |
child | Child | Extended childNode object. |
options | Options | @slidy/core options subset. |
translate | string | Basic translate required for any function { transform: translate } |
child
| Name | Type | Description |
|---|---|---|
i | number | Child index in array. |
index | number | Child index in core script. |
active | number | Calculated as options.loop ? cix : options.index. |
size | number | Calculated as size + gap by options.vertical. |
dist | number | Snap position distance. |
track | number | Move by slide size from its snap point in specified direction. |
turn | number | Calculated as -1 <- child.track / child.size -> 1 |
exp | number | Interpolated child.track as 0 <- exp -> 1. |
options
| Name | Type | Description |
|---|---|---|
index | number | Active slide index. |
position | number | Current position value. |
vertical | number | Children flow, calculated as 0 or any Number as true. |
reverse | number | The children reverse flow state: `-1 |
snap | Snap | The snap position value: "start", "center", "end", "deck", undefined. |
Animation presets
Predefined custom animations are available as separate package.
Limitations
Children (slide items)
absolutepositioning should not be applied. While the script uses coordinates from thechildNode, it breaks the script functionality completely;@slidy/coredoes not style the DOM, but keep in mind that there are some inline properties applied to the target node to provide functionality:
{
outline: none;
overflow: hidden;
user-select: none;
}