New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@rei/carousel-engine

Package Overview
Dependencies
Maintainers
0
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@rei/carousel-engine

A flexible, API-driven carousel framework designed for modularity and adaptability. CarouselEngine provides an abstraction layer that allows consumers to define their own adapters for transforming data into a carousel-ready format.

  • 1.0.0
  • latest
  • npm
  • Socket score

Version published
Maintainers
0
Created
Source

Carousel Engine is a flexible, adapter-driven Vue 3 carousel framework that leverages the Adapter Pattern to separate data transformation from rendering. This is a forked and re-architected version of @rei/recommendations-slider, designed for greater modularity and reusability.

📦 Installation

$ npm i @rei/carousel-engine

🚀 Usage

Using CarouselEngine involves three key steps:

  1. Define an Adapter (Transforms raw model data into a carousel format)
  2. Provide a Model (Pass structured data to the carousel)
  3. Handle Events (Optional) (Define custom event handlers for interactions)

1️⃣ Define an Adapter

An adapter maps raw model data to a structured carousel configuration.

// adapter.ts
import type { LifestyleModel, LifestyleSlide } from '.';
import type {
  CarouselAdapter,
  CarouselConfig,
  Slide,
} from '@rei/carousel-engine';

import SlideComponent from './LifestyleSlide.vue';

export const adapter: CarouselAdapter<LifestyleSlide> = (modelData) => {
  /**
   * Extracts slides from the raw model data.
   */
  const {
    slides: slideItems = [],
    slideStyle,
    slidesVisible = 4,
  } = modelData as Partial<LifestyleModel>;

  /**
   * Determines the carousel ID.
   */
  const carouselId = 'lifestyle';

  /**
   * Transforms raw items into an array of slides for the carousel.
   *
   * @type {Slide<LifestyleSlide>[]}
   */
  const slides: Slide<LifestyleSlide>[] = Array.isArray(slideItems)
    ? slideItems.map((slide, index) => ({
        key: `lifestyle-slide-${index}`,
        props: {
          ...slide,
          slideStyle,
          lastSlide: index === slideItems.length - 1,
        },
      }))
    : [];

  /**
   * Constructs the carousel model with the resolved slides and metadata.
   *
   * @type {CarouselConfig<LifestyleSlide>}
   */
  const carouselModel: CarouselConfig<LifestyleSlide> = {
    component: SlideComponent,
    slides,
    carouselId,
    description: 'Lifestyle carousel',
    slidesGap: parseInt(CdrSpaceThreeQuarterX, 10),
    slidesToShow: slidesVisible,
    focusSelector: ':first-child a',

    /**
     * A function that dynamically adjusts the number of slides to show
     * and scroll based on the client's screen width.
     *
     * @param {{ slidesToShow: Ref<number>, slidesToScroll: Ref<number> }} refs -
     *  An object containing references to the slidesToShow and slidesToScroll values.
     * @return {void}
     */
    resizeStrategy: ({ slidesToShow, slidesToScroll }) => {
      slidesToShow.value = window.innerWidth > 1024 ? slidesVisible : 2;
    },
  };

  return carouselModel;
};

export default adapter;

In a Vue component, pass the model and adapter to CarouselEngine. Your model is passed to your adapter, which transforms it into a structured carousel configuration.

<template>
  <CarouselEngine :model="model" :adapter="adapter" />
</template>

<script setup lang="ts">
import CarouselEngine from '@rei/carousel-engine';
import adapter from './adapter';

import lifestyleModelData from './mock.json';
import type { LifestyleModel } from './implementation/Lifestyle';

const model = lifestyleModelData as LifestyleModel;
</script>

3️⃣ Handle Events

Carousel Engine emits several named events:

  • arrowClick - Emitted when an arrow is clicked.
  • resize - Emitted when the carousel resize observer fires. When you want to adjust the carousel's internal state, like slidesToShow and slidesToScroll, define a resizeStrategy in your adapter, rather than attaching a listener to this event.
// handlers.ts
import type { CarouselArrowClickPayload } from '@rei/carousel-engine';
import type { LifestyleModel, LifestyleSlideClickPayload } from '.';

/**
 * Handles arrow click events in the carousel.
 * Determines scroll direction and formats analytics tracking data.
 *
 * @param {unknown} payload - The event payload containing navigation details.
 * @return {void}
 */
export function onArrowClick(payload: unknown): void {
  const { direction, event, model = {} } = payload as CarouselArrowClickPayload;
  const { slidesVisible, slideStyle } = model as Partial<LifestyleModel>;

  const scrollDirection =
    direction === 'right' ? 'forwardScroll' : 'backScroll';
  const scrollValue = `scroll-${direction}`;
  const analytics = {
    [scrollDirection]: scrollValue, // Scroll direction tracking key
    slidesVisible,
    slideStyle,
  };

  console.log('onArrowClick', { event, direction, analytics });
}

Attach the handler:

<template>
  <CarouselEngine
    :model="model"
    :adapter="adapter"
    @arrow-click="onArrowClick"
  />
</template>

<script setup lang="ts">
import CarouselEngine from '@rei/carousel-engine';

import { onSlideClick, onArrowClick } from './handlers';
</script>
Custom Events (Provide/Inject)

Carousel Engine supports custom events by using Provide/Inject. If you need to bubble an event to a parent component, CarouselEngine.vue provides the emitEvent function. In your components, you can Inject the emitEvent function and use it to emit custom events.

<template>
  <button class="slide__button" @click.once="onSlideClick"></button>
</template>
<script setup lang="ts">
import type { CarouselEventEmitter } from '@rei/carousel-engine';
import { CarouselEventKey } from '@rei/carousel-engine';

const emitEvent = inject(CarouselEventKey) as CarouselEventEmitter;

/**
 * Handles the click event on a slide, emitting a 'slideClick' event with the event details and the slide item.
 *
 * @param {Event} event - The click event that triggered this function.
 * @return {void}
 */
const onSlideClick = (event: Event) => {
  emitEvent?.('slideClick', {
    event,
    item: props,
  } as LifestyleSlideClickPayload);
};
</script>

Now, define a handler for the slideClick event:

import type { CarouselArrowClickPayload } from '@rei/carousel-engine';
import type { LifestyleModel, LifestyleSlideClickPayload } from '.';

/**
 * Handles slide click events in the carousel and logs analytics data.
 *
 * @param {unknown} payload - The event payload containing details about the clicked slide.
 * @return {void}
 */
export function onSlideClick(payload: unknown): void {
  const { event, item } = payload as LifestyleSlideClickPayload;

  const analytics = {
    target: item.cta.target,
    text: item.cta.text,
  };

  console.log('onSlideClick', { event, item, analytics });
}

Attach the handler:

<template>
  <CarouselEngine
    :model="lifestyleModelData"
    :adapter="LifestyleAdapter"
    @slide-click="onSlideClick"
    @arrow-click="onArrowClick"
  />
</template>

<script setup lang="ts">
import CarouselEngine from 'carousel-engine';
import LifestyleAdapter from './adapter';
import lifestyleModelData from './mock.json';
import { onSlideClick, onArrowClick } from './handlers';
</script>

🏗 Architectural Overview

Carousel Engine is built with a layered architecture that separates concerns into four key layers:

  • The Carousel Engine component acts as the orchestrator, managing carousel state, event handling, and rendering.
  • Handles carousel navigation, focus management, and slide transitions, while remaining agnostic to specific implementations.

2️⃣ Adapter Layer (Model Transformation & Customization)

  • Adapters define how raw model data is transformed into a standardized carousel structure.
  • Implements the Adapter Pattern, allowing different data formats to be consumed without modifying the core engine.

3️⃣ Handler Layer (Event Processing & Consumer Interactions)

  • Handlers allow consumers to define custom event logic for slides and navigation without modifying the core engine.
  • Arbitrary events can be emitted with Provide/Inject, enabling per-instance overrides.
  • Supports tracking analytics, logging, or triggering additional UI behaviors in a fully decoupled way.

4️⃣ Model-Driven Rendering (Data as the Source of Truth)

  • The entire carousel is driven by a structured model, making it highly flexible.
  • Consumers pass a model object and an adapter, and CarouselEngine dynamically constructs the carousel.
  • Enables easy A/B testing, content variations, and dynamic configurations without modifying components.

Examples

Check out the examples folder for more detailed examples. You can also run the local development environment to see how it works in SFCs:

git clone git@github.com:rei/carousel-engine.git
cd carousel-engine
npm ci
npm run dev

FAQs

Package last updated on 12 Feb 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc