@slidy/element
Version:
Simple, configurable & reusable carousel CustomElement
317 lines (238 loc) • 10.4 kB
Markdown
[](https://www.npmjs.com/package/@slidy/element)
[](https://bundlephobia.com/package/@slidy/element)
[](https://www.npmjs.com/package/@slidy/element)
[](https://github.com/Valexr/slidy/issues)
[](https://www.npmjs.com/package/@slidy/element)
# @slidy/element
Simple, configurable & reusable carousel CustomElement based on [@slidy/core](https://github.com/Valexr/slidy/tree/master/packages/core).
#### Try the [DEMO]
> - [Getting started](#getting-started)
> - [Usage](#usage)
> - [Options](#options)
> - [Events](#events)
> - [Methods](#methods)
> - [Styling](#styling)
## Getting started
The package is available via [NPM]:
```sh
npm i -D @slidy/element
```
or from [CDN]:
```html
<script src="https://unpkg.com/@slidy/element"></script>
```
Playground is available in svelte [REPL].
## Usage
CustomElement `<slidy-element>` is available via import as `MJS/CJS` module or via global `Window.Slidy` object props as `IIFE`.
### MJS/CJS module import
```html
<head>
<script type="module">
import 'https://unpkg.com/@slidy/core/dist/index.mjs'; // MJS module
// OR
import 'https://unpkg.com/@slidy/core/dist/index.cjs'; // CJS module
</script>
</head>
<slidy-element id="slidy" index="5">
<img src="..." width="..." height="..."/>
...
</slidy-element>
```
### IIFE as `Window` Object
window.Slidy object contain Slidy Class like `element` props, [@slidy/animation], [@slidy/easing] & [@slidy/media] functions.
```js
window.Slidy = {
animation, // animation functions
easing, // easing functions
element, // Slidy Class
media // global media store
}
```
```html
<head>
<script src="https://unpkg.com/@slidy/element/dist/index.js"></script>
</head>
<slidy-element id="slidy" index="5" snap="center">
<img src="..." width="..." height="..."/>
...
</slidy-element>
<script>
const animation = Slidy.animation.flip
const easing = Slidy.easing.cubic
const media = Slidy.media
const node = document.querySelector('#slidy')
node.setAttribute('easing', easing.toString())
// options set after attributes on init <slidy-element> & merged/rewrite
node.options = {animation: animation.toString()}
</script>
```
### As third party module in any frameworks
```html
<!-- Svelte -->
<script>
import '@slidy/element';
</script>
<slidy-element id="slidy" index="5" snap="center">
<img src="..." width="..." height="..."/>
...
</slidy-element>
```
## Options
All `options` are optional & can be passed through element attributes or like options keys. Options set after attributes on init `<slidy-element>` & merged/rewrite.
`animation` & `easing` functions also can be passed through attributes with: `key: function.tostring()` transformation.
If you need reversed flow use css rules on target node, like: `flex-flow: row-reverse / column-reverse`, `direction: rtl` or html attribute `dir="rtl"`.
If you need keyboard navigation just set `tabindex=0` on `<slidy-element>`.
⚠️ Don't positioning childs `absolute`, because @slidy use coordinates from childNodes. For deck flow use `options.snap: 'deck'`.
| Key | Default | Type | Description |
| :---------- | :---------- | :--------- | :---------- |
| `index` | `0` | `number` | Start index |
| `clamp` | `0` | `number` | Clamping sliding by index: `clamp - index + clamp` |
| `indent` | `1` | `number` | Sliding indent: part of gap padding both start/end edges of slide `gap * indent` |
| `sensity` | `5` | `number` | Sliding sensity: how many pixels to drag in the RAF `~16ms` to start move, `0` when sliding |
| `gravity` | `1.2` | `number` | Sliding gravity: `0(space) ~ 1(eath) ~ 2(underground)` |
| `duration` | `375` | `number` | Sliding duration in ms |
| `animation` | `undefuned` | `function` | Animation function: `AnimationFunc = (args: AnimationArgs) => Styles` - predefined in [@slidy/animation]. |
| `easing` | `undefined` | `function` | Easing function: `t value from 1 to 0` - predefined in [@slidy/easing]. |
| `snap` | `undefined` | `string` | Snapping side: `'start', 'center', 'end', 'deck', undefined`. Default clamp sliding by edges. |
| `axis` | `undefined` | `string` | Control coordinate axis: `'x', 'y'`. |
| `loop` | `false` | `boolean` | Infinite loop mode |
### Internal calculated - readonly
| 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` |
| `scrollable` | `number` | Children full size with gaps > target node size |
### Usage
```html
<head>
<script src="https://unpkg.com/@slidy/element/dist/index.js"></script>
</head>
<slidy-element id="slidy" index="5" snap="center">
<img src="..." width="..." height="..."/>
...
</slidy-element>
<script>
let animation = Slidy.animation.flip
easing = Slidy.easing.cubic
media = Slidy.media
node = document.querySelector('#slidy')
node.setAttribute('easing', easing.toString())
// options set after attributes on init <slidy-element> & merged/rewrite
node.options = {animation: animation.toString()}
</script>
```
## Events
Slidy instance reinit on every change childNodes.length in `on:mutate` event.
| Name | Detail | Description |
| :-------- | :------------------ | :---------- |
| `mount` | `{options}` | Fires when `node.children.length` & node.children isConnected |
| `resize` | `{ROE,options}` | Fires on resize target node `ROE: ResizeObserverEntry[]`|
| `mutate` | `{ML,options}` | Fires on mutation `childNodes` in target node `ML: MutationRecord[]`|
| `move` | `{index,position}` | Fires on any sliding |
| `index` | `{index}` | Fires on each index change: `index === changed.index` |
| `keys` | `{e.key}` | Fires if target node focusing and any key pressed. Predefined keys: `['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown']` is `defaultPrevented` & navigate `to(index + options.clamp)`. Focus not in core & can do programaticaly or with `tabindex` attribute on target node. |
| `update` | `{updated.options}` | Fires on each options update |
| `destroy` | `{node}` | Fires when async [`destroy()`](#methods) resolved or before target node unmounted from the DOM |
### Usage
```html
<head>
<script src="https://unpkg.com/@slidy/element/dist/index.js"></script>
</head>
<slidy-element id="slidy" index="5" snap="center" onmove="onMove">
<img src="..." width="..." height="..."/>
...
</slidy-element>
<script>
const node = document.querySelector('#slidy');
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>
```
## Methods
| Name | Arguments | Description |
| :---------- | :----------------- | :---------- |
| `to()` | `(index)` | Scroll to `index` |
| `init()` | `(node)` | Init slidy() instance |
| `update()` | `({option:value})` | Update any property in options |
| `destroy()` | `()` | Remove event listners, observers & defaulted props on `slidy()` instance |
### Usage
```html
<head>
<script src="https://unpkg.com/@slidy/core/dist/index.js"></script>
</head>
<slidy-element id="slidy" index="5" snap="center" onmove="onMove">
<img src="..." width="..." height="..."/>
...
</slidy-element>
<nav>
<button id="prev">←</button>
<button id="next">→</button>
</nav>
<script>;
const slidy = document.querySelector('#slidy');
const prev = document.querySelector('#prev');
const next = document.querySelector('#next');
slidy.update({ snap: 'center' })
prev.onclick = () => slidy.to(index - 1)
next.onclick = () => slidy.to(index + 1)
</script>
```
## Styling
`<slidy-element>` nested `@slidy/core` styles `outline: 0; overflow: hidden; user-select: none; -webkit-user-select:none;` & have base simple incapsulated styles. Also you can style it & his childs as native HTMLElements or you can pass CSSvariables props via `style` attribute or in css scope. For `<img>` children required pass `width/height` attributes.
### Incapsulated styles
```css
:host {
display: flex;
flex-flow: var(--flow);
gap: var(--gap, 1rem);
width: 100%;
height: var(--height, 20rem);
}
::slotted(*) {
flex: 0 0 var(--width, auto);
width: var(--width, auto);
height: 100%;
}
```
### CSS variables
| Name | Default | Description |
| :--------- | :------ | :----------------------- |
| `--flow` | `row` | Flex flow |
| `--width` | `auto` | Each children width |
| `--height` | `20rem` | `<slidy-element>` height |
| `--gap` | `1rem` | Gap between childs |
### Usage
```html
<head>
<script src="https://unpkg.com/@slidy/core/dist/index.js"></script>
<style>
#slidy {
--flow: row;
border: 1px solid red;
}
</style>
</head>
<slidy-element
id="slidy"
index="5"
snap="center"
style="--width: 100px; --height: 100px; --gap: 1rem;"
>
<img src="..." width="..." height="..."/>
...
</slidy-element>
```
MIT © [Valexr](https://github.com/Valexr)
[DEMO]: https://slidy-core.surge.sh
[NPM]: https://www.npmjs.com/package/@slidy/element
[CDN]: https://unpkg.com/@slidy/element/
[REPL]: https://svelte.dev/repl/4336a0d56f9049c98b85245a8cc33f7f
[@slidy/animation]: https://github.com/Valexr/Slidy/tree/master/packages/animation
[@slidy/easing]: https://github.com/Valexr/Slidy/tree/master/packages/easing
[@slidy/media]: https://github.com/Valexr/Slidy/tree/master/packages/media