@slidy/svelte
Version:
Simple, configurable & reusable carousel component built with SvelteJS
389 lines (295 loc) • 16 kB
Markdown
<div align="center">
<a href="https://www.npmjs.com/package/@slidy/svelte">
<img alt="npm package version" src="https://img.shields.io/npm/v/@slidy/svelte?style=flat-square" />
</a>
<a href="https://www.npmjs.com/package/@slidy/svelte">
<img alt="types included" src="https://img.shields.io/npm/types/@slidy/svelte?style=flat-square" />
</a>
<a href="https://www.npmjs.com/package/@slidy/svelte">
<img alt="downloads count" src="https://img.shields.io/npm/dm/@slidy/svelte?style=flat-square" />
</a>
<a href="https://www.npmjs.com/package/@slidy/svelte">
<img alt="licence" src="https://img.shields.io/npm/l/@slidy/svelte?style=flat-square" />
</a>
<a href="https://bundlephobia.com/package/@slidy/svelte">
<img alt="minzipped size" src="https://img.shields.io/bundlephobia/minzip/@slidy/svelte?style=flat-square" />
</a>
<a href="https://bundlephobia.com/package/@slidy/svelte">
<img alt="dependency count" src="https://badgen.net/bundlephobia/dependency-count/@slidy/svelte?style=flat-square" />
</a>
</div>
# @slidy/svelte
Simple, configurable & reusable carousel component built with SvelteJS based on [@slidy/core][core-package].
Try the [demo].
## Getting started
The package is available via [npm]:
```
npm i @slidy/svelte
```
Playground is available in [REPL].
## Usage
The most simple way to get started is to use named import of `<Slidy />` component:
```svelte
<script>
import { Slidy } from "@slidy/svelte";
const slides = [
{
id: 1,
width: 800,
height: 1200,
src: "static/img/some-image.webp",
},
];
</script>
<Slidy {slides} />
```
All props are optional. The only property to get started is `slides` - an array of objects with image related data.
## Core Component
`Core` is a wrapper component for [@slidy/core][core-package] available via named import. It is best to use to build up the custom component for specific needs or when just the basic functionality is needed.
```svelte
<script>
import { Core } from "@slidy/svelte";
</script>
<Core>
<!-- your carousel items passed via slot -->
</Core>
```
### Core Component API
| Property | Default | Type | Description |
| :------------ | :--------------: | :--------: | :------------------ |
| `animation` | `undefined` | `AnimationFunc ` | Custom slide animation. |
| `axis` | `"x"` | `"x" | "y"` | The scroll direction. |
| `clamp` | `0` | `number` | Defines number of items to jump over at one slide action. |
| `className` | `""` | `string` | Passes the `class` to the node. |
| `duration` | `450` | `number` | Slide transitions duration value. |
| `easing` | `undefined` | `(t: number => number)` | Inertion scroll easing behaviour. |
| `gravity` | `1.2` | `number` | Scroll inertia value. |
| `indent` | `0` | `number` | Custom scroll indent value, calculates as `gap * indent`. |
| `index` | `0` | `number` | The index of the initial slide. |
| `loop` | `false` | `boolean` | Makes the slideshow continious. |
| `plugins` | `[]` | `PluginFunc[]` | The array of plugins. |
| `position` | `0` | `number` | The current position value of the carousel. |
| `sensity`| `5` | `number` | Defines the sliding sensity as the number of pixels required to drag. |
| `snap` | `undefined` | `"start" | "center" | "end" | "deck"` | Enforces the scroll stop positions. |
| `tag` | `"ol"` | `string` | The HTML tag name to render. |
For TypeScript users there is the `SlidyCoreOptions` interface available via named import.
## Slidy Component
`<Slidy />` component uses `<Core />` internally and provides more features expected from carousel.
### Slidy Component API
The `<Slidy />` component interface extends the `<Core />`. There are a list of additional options available:
| Property | Default | Type | Description |
| :------- | :-----: | :--: | :---------- |
| `arrows` | `true` | `boolean` | Renders the arrow button controls for accessible slide navigation. |
| `background` | `false` | `boolean` | Sets `background-image` instead of `<img />` elements to display slides. |
| `classNames` | `SlidyStyles` | `SlidyStylesDefault` | The class names object used over the component. |
| `getImgSrc` | `item => item.src` | `function` | The slide's `src` attribute getter. |
| `getThumbSrc` | `item => item.src` | `function` | The thumbnail's `src` attribute getter. |
| `groups` | `0` | `number` | Controls the number of items displayed per viewport. |
| `i18n` | `i18nDefaults` | `I18NDict` | The i18n localization dictionary. |
| `navigation` | `false` | `boolean` | Renders the navigation controls for pagination-like slide navigation. |
| `progress` | `false` | `boolean` | Renders the progress bar. |
| `slides` | `[]` | `Slides[]` | An array of objects with image metadata. |
| `thumbnail` | `false` | `boolean` | Renders the thumbnail navigation panel. |
| `vertical` | `false` | `boolean` | Defines the slides flow by using `aria-orientation`. |
By default component works with images. Image object should contain `width` and `height` attributes to prevent layout shifts and `alt` for accessibility.
## Styling
### Extending/Overriding classes
To extend default component styles use `classNames` property. Default classes are available via object, that can be extended or overridden:
```svelte
<script>
import { Slidy, classNames } from "@slidy/svelte";
</script>
<Slidy
classNames={{
root: `${classNames.root} custom-class`,
...classNames
}}
/>
```
The `classNames` consist of `{ target: className }` pairs:
| Target | Default class | Description |
| :-------- | :----------------: | :-----------|
| arrow | `slidy-arrow` | Arrow controls. |
| autoplay | `slidy-autoplay` | Autoplay control. |
| counter | `slidy-counter` | Slide progress counter. |
| img | `slidy-img` | Slide image node. |
| nav | `slidy-nav` | Slide navigation panel. |
| nav-item | `slidy-nav-item` | Navigtion panel item. |
| overlay | `slidy-overlay` | Slides overlay node. |
| progress | `slidy-progress` | Slide progress bar. |
| progress-handle | `slidy-progress-hadle` | Slide progress bar control handle. |
| root | `slidy` | Component's root node. |
| slide | `slidy-slide` | Slide item node. |
| slides | `slidy-slides` | Slides list node. |
| thumbnail | `slidy-thumbnail` | Thumbnail item. |
| thumbnail | `slidy-thumbnails` | Thumbnails bar. |
The `classNames` object is available via [context](https://svelte.dev/docs#run-time-svelte-getcontext) using `classNames` key.
### Custom Properties API
For easier style customization `Slidy` provides a set of predefined custom properties to inherit:
List of available public custom properties:
| Property | Default | Type | Description |
| :----------------------------- | :--------: | :---------: | :--------------------------------------------------- |
| `--slidy-arrow-bg` | #4e4e4ebf | `<color>` | The arrow control background color. |
| `--slidy-arrow-bg-hover` | #4e4e4e54 | `<color>` | The arrow control hover background color. |
| `--slidy-arrow-icon-color` | currentColor | `<color>` | The arrow control icon fill color. |
| `--slidy-arrow-size` | 24px | `<length>` | The arrow controls size. |
| `--slidy-counter-bg` | #4e4e4ebf | `<color>` | The counter's background color. |
| `--slidy-focus-ring-color` | #c9c9c9e6 | `<color>` | Focus ring color for all focusable elements. |
| `--slidy-height` | 100% | `<length>` | The height of the component's node. |
| `--slidy-nav-item-color` | white | `<color>` | The navigation elements color. |
| `--slidy-nav-item-radius` | 0.35em | `<length>` | The navigation elements border radius. |
| `--slidy-nav-item-size` | 16px | `<length>` | The navigation elements size. |
| `--slidy-progress-thumb-color` | #c44f61 | `<color>` | The progress bar active track color. |
| `--slidy-progress-track-color` | #96969680 | `<color>` | The progress bar track color. |
| `--slidy-progress-track-size` | 10px | `<length>` | The progress bar height. |
| `--slidy-slide-aspect-ratio` | unset | `<int/int>` | Defines the slide aspect-ratio. |
| `--slidy-slide-bg-color` | darkgray | `<color>` | The placeholder background color for loading images. |
| `--slidy-slide-gap` | 1rem | `<length>` | The gap between items in carousel. |
| `--slidy-slide-height` | 100% | `<length>` | The carousel items height. |
| `--slidy-slide-object-fit` | cover | - | The carousel items (images) resize behaviour. |
| `--slidy-slide-radius` | 1rem | `<length>` | The slide's border radius value. |
| `--slidy-slide-width` | auto | `<length>` | The carousel items width. |
| `--slidy-thumbnail-radius` | 0.5rem | `<length>` | The thumbnail `border-radius` value. |
| `--slidy-thumbnail-size` | 50px | `<length>` | The thumbnail panel size. |
| `--slidy-width` | 100% | `<length>` | The width of the component's node. |
There are two options:
#### --style-props
Svelte supports passing down custom properties to component via [`--style-props`][svelte-custom-props]:
```svelte
<Slidy --slidy-slide-gap="1rem" />
```
Bear in mind that this way Svelte wraps the component in extra `<div />` with `display: contents`.
#### Inherited custom properties
More optimal way is to use cascade. All supported custom properties starts with `--slidy-`. For example, to recolor navigation controls, let the component inherit a `--slidy-nav-item-color` custom property from any parent:
```svelte
<div class="parent">
<Slidy />
</div>
<style>
.parent {
--slidy-navigation-color: red;
}
</style>
```
Or just pass a class with a set of custom properties:
```svelte
<script>
import { Slidy, classNames } from "@slidy/svelte";
</script>
<Slidy
classNames={{
root: `${classNames.root} .some-class`,
...classNames
}}
/>
<style>
.some-class {
--slidy-navigation-color: red;
--slidy-nav-item-size: 1rem;
}
</style>
```
## Slots
### `arrow`
Customizes the content of the default arrow controls.
### `arrows`
Provides a slot for custom arrow buttons.
If the nodes are `<button /> ` and the `data-step` attribute is present, the event listener is not needed. Just provide the values `-1` and `1` for `data-step` on custom buttons.
Also, there are `grid-area` is present in the layout for this custom controls: `prev-slide` and `next-slide` respectively.
```svelte
<Slidy>
<svelte:fragment slot="arrows">
<button data-step="-1"> Show the previous slide </button>
<button data-step="1"> Show the next slide </button>
</svelte:fragment>
</Slidy>
<style>
button:first-of-type {
grid-area: prev-slide;
}
button:last-of-type {
grid-area: next-slide;
}
</style>
```
### `default`
Usually the default markup is not enough. The `default` slot solves this problem. To use custom slide markup slot expose each `slides` prop item as `let:item` directive.
```svelte
<Slidy let:item>
<figure>
<img src={item.src} alt={item.figcaption} />
<figcaption>
{item.figcaption}
</figcaption>
</figure>
</Slidy>
```
### `nav-item`
Provides a slot for custom pagination buttons.
Slot receives optional `index` and `active` props for proper functionality.
Custom navigation item should be a `<button />` and have `data-index` attribute to function. Otherwise, control the component [externally](#external-controls).
```svelte
<Slidy let:active let:index>
<button slot="nav-item" data-index={index} {active} {index} />
</Slidy>
```
### `overlay`
Slot to display content overlaid content. It covers the slides area and can be customized by overriding the `.slidy-overlay`. For example, it is used to display the counter.
```svelte
<Slidy>
<svelte:fragment slot="overlay">
<button> Share </button>
</svelte:fragment>
</Slidy>
```
### `thumbnail`
_Work in progress_
## Events
The component forwards custom events:
| Name | Description | Event detail |
| :-------- | :------------------------------- | :-----------------------------------: |
| `destroy` | Component is destroyed. | `node` |
| `index` | The current slide index changes. | `{ index: number, position: number }` |
| `keys` | The key pressed on focus. | `event.code` |
| `mount` | Component is mounted to the DOM. | `{ childs, options }` |
| `move` | Navigation occurs. | `{ index: number, position: number }` |
| `resize` | Component's dimentions changes. | `{ node, options }` |
| `update` | Component's props changes. | `options` |
## i18n
To modify all texts used in the component use pass the dictionary as `i18n` prop. For the sake of accessibility, it is recommended translating defaults:
| Key | Default | Event detail |
| :-------- | :------------------------------ | :-----------------------------------: |
| `carousel`| "carousel" | `aria-label` of a root element. |
| `counter` | "%s of %s" | `aria-label` of each slide as {slide number} of {slide length} |
| `first` | "Go to the first slide" | `aria-label` of the first item at the navigation. |
| `last` | "Go to the last slide" | `aria-label` of the last item at the navigation. |
| `next` | "Go to the next slide" | `aria-label` of the arrow control. |
| `play` | "Start autoplay" | `aria-label` of the autoplay control. |
| `prev` | "Return back to previous slide" | `aria-label` of the arrow control. |
| `slide` | "Slide" | `aria-roledescription` of each slide item. |
| `slideN` | "Go to the slide %s" | `aria-label` of pagination of each slide item. |
| `stop` | "Stop autoplay" | `aria-label` of the autoplay control. |
## Recipes
### External controls
It is possible to control the navigation of the `Slidy` instance from the parent component via binding.
There are two variables available to control the component externally: `index` and `position`. Declare the variables to hold the values and bind them to the instance for the carousel control.
```svelte
<script>
import { Slidy } from "svelte-slidy";
let index = 0;
let position = 0;
</script>
<button on:click={() => (index += 1)}> Next slide </button>
<button on:click={() => (position += 50)}> Move </button>
<Slidy bind:index bind:position />
```
## Possible issues
- Slides should not have `absolute` positioning, otherwise the [core-package][] script won't get correct dimentions;
- Using the `background` option usually is not recommended. In case you need to use it, specify the slide sizes with custom properties: `width` and `height`, or just `aspect-ratio`.
## License
MIT © [EricRovell](https://github.com/EricRovell)
[core-package]: https://github.com/Valexr/slidy/tree/master/packages/core
[demo]: https://valexr.github.io/Slidy
[npm]: https://www.npmjs.com/package/@slidy/svelte
[repl]: https://svelte.dev/repl/de699aa1f8c04874b0402352ac93df96
[svelte-custom-props]: https://svelte.dev/docs#template-syntax-component-directives---style-props