С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-reverse
CSS property;direction: rtl
CSS 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)
absolute
positioning should not be applied. While the script uses coordinates from thechildNode
, it breaks the script functionality completely;@slidy/core
does 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;
}