Carousel

Набор компонентов для создания списков с прокруткой (галерей).

Storybook

Состав

При сборке карусели используйте структуру, в которой корневым элементом является Carousel со вложенными в него CarouselItem или CarouselCol. При необходимости отображения элементов карусели в сетке, оборачивайте карусель в CarouselGridWrapper.

CarouselLite

CarouselVirtual

Рекомендуется использовать вместе с хуком, который возвращает "виртуализированный" список элементов.

import { useVirtual } from '@salutejs/use-virtual';

Многие фичи обычной Carousel поддерживаются внутри данного хука:

  • useVirtual возвращает активный элемент ( = detectActive)
  • onIndexChange, onDetectActiveItem легко реализовать по месту использования, учитывая доступ к активному элементу из хука
  • scrollAlign надо передавать в useVirtual
  • paddingStart, paddingEnd также передаются в useVirtual (px)

Некоторые фичи обычной Carousel не поддерживаются:

  • animatedScrollByIndex
  • scrollSnapType
  • throttleMs
  • debounceMs
  • scaleCallback
  • scaleResetCallback

CarouselGridWrapper

CarouselItem

CarouselItemVirtual

CarouselCol

Использование

CSS Scroll Snap

  1. В компоненте Carousel укажите свойство scrollSnapType:
MyGallery.tsx
import React from 'react';
import { Carousel } from '@salutejs/plasma-ui';

export const MyGallery = () = (
<Carousel scrollSnapType="mandatory">
// Элементы карусели помещаются здесь
</Carousel>
);
  1. Также укажите свойство scrollSnapAlign для элемента карусели:
MyGallery.tsx
import React from 'react';
import { CarouselItem } from '@salutejs/plasma-ui';

export const MyGalleryItem = ({ children }) => (
<CarouselItem scrollSnapAlign="center">{children}</CarouselItem>
);

Определение центрального элемента

Карусель может определять активный элемент при прокрутке. Для этого укажите свойства detectActive, detectThreshold и обработчик onIndexChange:

MyGallery.tsx
import React from 'react';
import { Carousel } from '@salutejs/plasma-ui';

export const MyGallery = () = (
<Carousel detectActive detectThreshold={0.5} onIndexChange={(index) => console.log(index)}>
// Элементы карусели помещаются здесь
</Carousel>
);

Стилизация центрального элемента

Элементы видимой части (viewport) можно стилизовать, например, увеличивать или менять *прозрачность.

В момент прокрутки карусели (с помощью колесика мыши, стрелок пульта или касанием) с определенной периодичностью вызывается обработчик скролла, который на основании положения элемента относительно viewport (внутренние границы карусели) вызывает тот или иной коллбек:

НазваниеОписаниеАргументыВозвращаемое значение
stylingCallbackОбработчик для элементов внутри viewport. Коллбек вызывается для видимого элемента, к нему применяется необходимая стилизация.itemEl: HTMLElement, slot: numbervoid
stylingResetCallbackОбработчик для элементов вне viewport. Элемент невидим, стилизация сбрасывается.itemEl: HTMLElementvoid

Для обозначения позиции элемента внутри viewport, карусель использует значение slot:

  • 0 равен центральному элементу;
  • -1 и 1 первый слева и справа от центрального;
  • -2 и 2 и т.д., соответственно, для второго и далее.
MyGallery.tsx
import React from 'react';
import { Carousel } from '@salutejs/plasma-ui';

/**
* Функция увеличения центрального элемента.
* Предположим, что у нас 5 элементов в внутри `viewport`.
* Тогда ряд slots будет таким: -2 -1 0 1 2.
* Центральный элемент примет opacity = 1, боковые - opacity = 0.5, а крайние слева и справа - opacity = 0
*/
const stylingCallback = (itemEl: HTMLDivElement, slot: number) => {
itemEl.style.opacity = `${1 - Math.abs(slot) / 2}`;
};

/**
* Функция сброса стилей элементов вне `viewport`.
*/
const stylingResetCallback = (itemEl: HTMLDivElement) => {
itemEl.style.opacity = '';
};

export const MyGallery = () = (
<Carousel stylingCallback={stylingCallback} stylingResetCallback={stylingResetCallback}>
// Элементы карусели помещаются здесь
</Carousel>
);
  • В данном примере используются Grid и CSS Scroll Snap.
  • В корне приложения необходимо разместить DeviceThemeProvider.
  • В качестве основного блока разметки контейнер (Container), а колонки (Col) помещаются в строки (Row).
  • Карусель поддерживает определение (detectActive) активного элемента.
Live Editor

Result

Пример использования CarouselLite

Live Editor

Result

Карусель с "виртуализированным" списком элементов

Если ваша карусель содержит большое количество элементов, рекомендуем использовать "виртуализацию". Этот подход позволяет рендерить только то количество элементов, которое помещается во вьюпорт. Это позволит значительно сократить время на первый и последующие рендеры карусели.

Live Editor

Result

Доступность

В элемент карусели добавьте атрибут aria-label, со значением, обозначающим текущую позицию в списке:

<Carousel>
{items.map((item, i) => <CarouselItem aria-label={`${i + 1} из ${items.length}`} />)}
</Carousel>