С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;
}