97 lines
3.1 KiB
Markdown
97 lines
3.1 KiB
Markdown
# @ilia/carousel
|
||
|
||
Tiny, framework-agnostic scroll-snap carousel. Zero runtime deps. Native scroll
|
||
handles touch/momentum, CSS handles snap + motion, JS is a thin layer.
|
||
|
||
- **core** ≤1 KB gzip · **dots** ≤0.6 KB · **autoplay** ≤0.6 KB
|
||
- Ships **unminified** ESM — your bundler minifies.
|
||
|
||
## Install
|
||
|
||
This package lives on a private Gitea registry. Point the `@ilia` scope at it:
|
||
|
||
```
|
||
# .npmrc
|
||
@ilia:registry=https://git.allmy.work/api/packages/ilia/npm/
|
||
```
|
||
|
||
```bash
|
||
yarn add @ilia/carousel
|
||
```
|
||
|
||
## Entry points
|
||
|
||
| Import | What |
|
||
|---|---|
|
||
| `@ilia/carousel` | `createCarousel(track)` core |
|
||
| `@ilia/carousel/dots` | `dots()` — Firefox/legacy dot fallback (self-gates) |
|
||
| `@ilia/carousel/autoplay` | `autoplay()` — reduce-motion-aware auto-advance |
|
||
| `@ilia/carousel/carousel.css` | snap track, native markers, opt-in `.fx` effect |
|
||
|
||
## Usage
|
||
|
||
```html
|
||
<div class="track" id="carousel">
|
||
<div class="slide">…</div>
|
||
<div class="slide">…</div>
|
||
<div class="slide">…</div>
|
||
</div>
|
||
<button id="prev" aria-label="Previous">‹</button>
|
||
<button id="next" aria-label="Next">›</button>
|
||
<!-- Firefox/legacy dot fallback; native ::scroll-marker owns dots elsewhere -->
|
||
<div id="dots" aria-label="Choose slide">
|
||
<button aria-label="Slide 1"></button>
|
||
<button aria-label="Slide 2"></button>
|
||
<button aria-label="Slide 3"></button>
|
||
</div>
|
||
```
|
||
|
||
```ts
|
||
import { createCarousel } from '@ilia/carousel';
|
||
import { dots } from '@ilia/carousel/dots';
|
||
import { autoplay } from '@ilia/carousel/autoplay';
|
||
import '@ilia/carousel/carousel.css';
|
||
|
||
const track = document.getElementById('carousel');
|
||
const c = createCarousel(track);
|
||
|
||
// Arrows are just your own handlers — no module needed.
|
||
document.getElementById('next').onclick = () => c.next();
|
||
document.getElementById('prev').onclick = () => c.prev();
|
||
|
||
// Dots: no-ops where native ::scroll-marker exists (no double dots).
|
||
dots(c, document.getElementById('dots'));
|
||
|
||
// Opt-in auto-advance. Provide a visible pause control (see a11y note).
|
||
const stop = autoplay(c, { interval: 4000, root: track });
|
||
```
|
||
|
||
Add the opt-in scroll-driven effect with `class="track fx"` — it degrades to plain
|
||
snap where `animation-timeline: view()` is unsupported.
|
||
|
||
## Accessibility
|
||
|
||
- `autoplay()` **never starts** under `prefers-reduced-motion: reduce`, and the `.fx`
|
||
effect + smooth scrolling are gated behind `@media (prefers-reduced-motion: no-preference)`.
|
||
- If you use `autoplay()`, you **must** provide a visible pause/stop control
|
||
(WCAG 2.2.2) — wire it to the returned `stop()`.
|
||
- Give dot buttons accessible labels (`aria-label`).
|
||
|
||
## Browser support
|
||
|
||
| Feature | Chrome | Safari | Firefox |
|
||
|---|---|---|---|
|
||
| `scroll-snap` + core path | ✅ | ✅ | ✅ |
|
||
| `::scroll-marker` native dots | ✅ 135+ | ✅ 18.2+ | ⚠️ → JS `dots()` fallback |
|
||
| scroll-driven `.fx` | ✅ | ⚠️ partial → plain snap | ✅ |
|
||
|
||
Index tracking uses IntersectionObserver (universal today); a `scrollsnapchange`
|
||
upgrade is deferred until Firefox ships it.
|
||
|
||
## Release
|
||
|
||
```bash
|
||
npm version <patch|minor|major>
|
||
git push --follow-tags # CI verifies, runs e2e, publishes on the v* tag
|
||
```
|