npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@shelamkoff/carousel

v1.0.0

Published

Position-first framework-agnostic carousel with composable plugins

Readme

@shelamkoff/carousel

Независимая от UI-фреймворков карусель с позиционной моделью, адаптивной раскладкой, зацикливанием, отменяемыми переходами, типизированными событиями и подключаемыми плагинами. Версия 1.0.0 поставляется как ESM-пакет для современных браузеров.

English README

Установка

npm install @shelamkoff/carousel @shelamkoff/event-bus

Один раз подключите обязательные стили:

import '@shelamkoff/carousel/styles.css'

Экспорт carouselStylesUrl позволяет приложению самостоятельно создать элемент <link>.

Быстрый старт

<div id="gallery"></div>
import {
  Carousel,
  createArrows,
  createDots,
  createKeyboard,
  createSwipe,
} from '@shelamkoff/carousel'
import '@shelamkoff/carousel/styles.css'

const carousel = new Carousel('#gallery', [
  {
    content: () => Object.assign(document.createElement('img'), {
      src: '/photos/forest.jpg',
      alt: 'Лес',
    }),
    thumb: '/photos/forest-thumb.jpg',
  },
  { content: '<p>Доверенная разметка приложения</p>' },
], {
  loop: true,
  gap: 16,
  plugins: [
    createArrows(),
    createDots(),
    createKeyboard(),
    createSwipe({ mouse: true }),
  ],
})

const unsubscribe = carousel.on('slide:change', ({ index, slide }) => {
  console.log(index, slide.meta)
})

carousel.next()

// При освобождении ресурсов:
unsubscribe()
carousel.destroy()

Контейнером может быть HTMLElement или CSS-селектор. Если селектор не находит элемент, конструктор выбрасывает исключение.

Данные слайда

interface SlideData {
  content: string | HTMLElement | (() => HTMLElement)
  thumb?: string
  lazy?: boolean
  meta?: Record<string, unknown>
}
  • Функция рендеринга — предпочтительный вариант для динамических или недоверенных данных.
  • Переданный HTMLElement перемещается в карусель, а не клонируется.
  • Строка интерпретируется как HTML и считается доверенной конфигурацией разработчика.
  • thumb использует плагин миниатюр, lazy — ленивая загрузка, а meta остаётся метаданными приложения.

Конфигурация

| Поле | Тип | По умолчанию | Назначение | | --- | --- | --- | --- | | slidesPerView | number | 1 | Количество одновременно видимых слайдов. Значение должно быть положительным. | | slidesPerScroll | number \| 'auto' | 1 | Шаг навигации. 'auto' использует текущее количество видимых слайдов. | | gap | number | 0 | Расстояние между слайдами в CSS-пикселях. | | transition | 'slide' \| 'fade' | 'slide' | Способ перехода. В режиме fade одновременно отображается один слайд. | | transitionDuration | number | 400 | Длительность перехода в миллисекундах. | | loop | boolean | false | Включает циклическую навигацию с техническими клонами. | | startIndex | number | 0 | Начальный логический индекс. Используется только при создании. | | breakpoints | Record<number, Partial<CarouselResponsiveOptions>> | нет | Переопределения, действующие начиная с указанной ширины области просмотра. | | plugins | CarouselPlugin[] | [] | Плагины, устанавливаемые при создании. |

Настройки контрольной точки переопределяют базовые. При смене контрольной точки карусель сохраняет текущий логический слайд, отменяет устаревшую анимацию и перестраивает раскладку.

const carousel = new Carousel('#gallery', slides, {
  slidesPerView: 1,
  slidesPerScroll: 'auto',
  breakpoints: {
    640: { slidesPerView: 2, gap: 12 },
    1024: { slidesPerView: 4, gap: 20 },
  },
})

Публичный API

| Метод | Результат | Назначение | | --- | --- | --- | | use(plugin) | this | Устанавливает плагин. Имена плагинов должны быть уникальны. | | getPlugin(name) | плагин или undefined | Возвращает публичный объект установленного плагина. | | next() / prev() | void | Перемещает карусель на текущий шаг прокрутки. | | goTo(index) | void | Переходит к логическому индексу слайда. | | getIndex() | number | Возвращает внутренний индекс отрисовки. В циклическом режиме обычно нужен getRealIndex(). | | getRealIndex() | number | Возвращает логический индекс в исходном массиве. | | getSlide(index?) | слайд или null | Возвращает слайд; без индекса — текущий. | | getSlides() | SlideData[] | Возвращает защитную копию массива слайдов. | | addSlide(slide, index?) | void | Добавляет слайд и перестраивает раскладку. | | removeSlide(index) | void | Удаляет логический слайд и корректирует текущий индекс. | | update(options) | void | Меняет поведение и раскладку. Поля plugins и startIndex намеренно не принимаются. | | on(event, handler) | функция отписки | Подписывает обработчик на событие. | | off(event, handler) | void | Удаляет конкретный обработчик. | | once(event, handler) | функция отписки | Подписывает обработчик на одно срабатывание. | | destroy() | void | Отменяет анимации, уничтожает плагины, удаляет созданный DOM и обработчики. |

После destroy() экземпляр использовать нельзя. Для повторного монтирования создайте новую карусель.

События

| Событие | Данные | | --- | --- | | slide:beforeChange | { fromIndex, toIndex } | | slide:change | { index, prevIndex, slide } | | transition:start | { fromIndex, toIndex } | | transition:end | { index } | | resize | { slidesPerView } | | autoplay:start / autoplay:stop | без данных | | slide:lazyload | { index, element } | | slide:error | { index, error } | | destroy | без данных |

Ошибка отрисовки или ленивой загрузки изолируется в соответствующем слайде и передаётся через slide:error.

Встроенные плагины

  • Стрелки — кнопки перехода; на границах скрываются по умолчанию.
  • Точки — нажимаемая пагинация.
  • Миниатюры — нижняя или боковая навигация.
  • Клавиатура — по умолчанию обрабатывает клавиши только внутри карусели.
  • Жесты — сенсорный ввод, указатель, сопротивление и необязательное перетаскивание мышью.
  • Автовоспроизведение — интервальное переключение с паузой при наведении и взаимодействии.
  • Ленивая загрузка — загрузка изображений через IntersectionObserver и предварительная подгрузка.
  • Параллакс — визуальное смещение, зависящее от позиции.

Плагин подключается через plugins или use(). Один экземпляр плагина с состоянием может принадлежать только одной активной карусели; для нескольких каруселей создавайте отдельные объекты.

Создание плагина

Плагин содержит уникальное поле name, метод install(context) и необязательный destroy():

export function createProgressPlugin() {
  let element = null

  return {
    name: 'progress',

    install(context) {
      element = document.createElement('output')
      element.className = 'carousel-progress'
      element.setAttribute('aria-live', 'polite')

      const render = () => {
        element.textContent = `${context.getRealIndex() + 1} / ${context.getSlideCount()}`
      }

      context.getRoot()?.append(element)
      context.on('slide:change', render)
      context.on('resize', render)
      render()
    },

    destroy() {
      element?.remove()
      element = null
    },
  }
}

Замороженный контекст предоставляет подписки на события с автоматическим владением, команды навигации, состояние и вычисленные настройки только для чтения, актуальные ссылки на DOM, позиционные методы для жестов и эффектов, а также refreshLayout(). Подписки контекста удаляются автоматически. Собственный DOM, глобальные обработчики, наблюдатели, таймеры, кадры анимации, объектные URL и сторонние экземпляры плагин освобождает в destroy().

Если install() выбрасывает исключение, карусель откатывает подписки и вызывает очистку плагина. Поэтому destroy() должен быть безопасен и после частичной установки.

Граница безопасности

Строковые slide.content и пользовательская HTML-разметка стрелок вставляются как HTML. Передавайте туда только доверенную разметку разработчика. Для пользовательских данных создавайте элемент через textContent или предварительно очищайте значение.

Демо

Из каталога пакета:

npm install
npm run demo

Или из корня рабочего пространства:

npm run demo:carousel

Откройте http://127.0.0.1:4173/carousel/demo.html. Страница проверяет основную навигацию, адаптивный многоэлементный режим, зацикливание и автовоспроизведение, затухание, миниатюры, пользовательскую тему и фиксированный шаг.

Экспорты пакета

  • @shelamkoff/carousel — JavaScript API и объявления TypeScript.
  • @shelamkoff/carousel/styles.css — обязательные стили карусели.
  • @shelamkoff/carousel/package.json — метаданные пакета.

Лицензия

MIT.