# content-blocks-builder/trunk/src/features/carousel/carousel-script.js

Content Blocks Builder – Create blocks, repeater blocks with carousel, grid, popup layouts, version trunk. 983 lines.

- Page: https://pluginprobe.com/plugins/content-blocks-builder/trunk/code/src/features/carousel/carousel-script.js
- Raw: https://pluginprobe.com/plugins/content-blocks-builder/trunk/raw/src/features/carousel/carousel-script.js
- Modified: 2026-08-05T07:16:28+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/content-blocks-builder/trunk/code/src/features/carousel/carousel-script.js#L10-L20`.

```javascript
import {
  BaseComponent,
  exposeComponent,
  triggerEvent,
  parseJSON,
} from "../../utils/dom";

/**
 * External dependencies
 */
import Swiper from "swiper";

import {
  Navigation,
  Pagination,
  Scrollbar,
  A11y,
  Autoplay,
  Thumbs,
  EffectFade,
  EffectCube,
  EffectFlip,
  EffectCoverflow,
  EffectCreative,
  EffectCards,
} from "swiper/modules";

Swiper.use([
  Navigation,
  Pagination,
  Scrollbar,
  A11y,
  Autoplay,
  Thumbs,
  EffectFade,
  EffectCube,
  EffectFlip,
  EffectCoverflow,
  EffectCreative,
  EffectCards,
]);

/**
 * Internal dependencies
 */
import { deepMerge, compose, createStyleManager } from "./utils-for-frontend";

class CarouselScript extends BaseComponent {
  constructor(element, options = {}) {
    // Get this._element and this._config
    super(element, options);

    // Bail if the element is not a DOM node
    if (!element) {
      return;
    }

    // Already initialized.
    this.cbbCarouselId = element.dataset.cbbCarouselId;
    if (this.cbbCarouselId && this.slider) {
      return this;
    }

    // Store the main element
    this.sliderElement = this._element;

    // Store the original source
    this.originalSource = element.cloneNode(true);

    // Get the owner document
    this.document = element.ownerDocument;

    // Cache the config
    this.settings = this._config;
    const { datasetSelector } = this.settings;

    // Get the datasetElement
    this.datasetElement = datasetSelector
      ? element.querySelector(datasetSelector) || element
      : element;

    // Get slider options
    this.sliderOptions = this.getSliderOptions(options?.sliderOptions);

    // The slider instance
    this.slider = null;

    // Kick start
    this.init();
  }

  static get NAME() {
    return "carousel";
  }

  defaultConfig() {
    return {
      selector: ".js-carousel-layout",
      wrapperSelector: ".carousel__inner",
      itemSelector: ".is-carousel-item",
      containerClass: "swiper",
      wrapperClass: "swiper-wrapper",
      itemClass: "swiper-slide",
      paginationClass: "swiper-pagination",
      navigationNextClass: "swiper-button-next",
      navigationPrevClass: "swiper-button-prev",
      scrollbarClass: "swiper-scrollbar",
      preloadClass: "cbb-carousel-preload",
      instanceId: "cbb-carousel-1",
      datasetSelector: "",
    };
  }

  getSliderOptions(options) {
    const slideChangeStart = (swiper) =>
      triggerEvent(window, "cbb.carousel.slideChangeTransitionStart", {
        swiper,
      });

    const slideChangeEnd = (swiper) =>
      triggerEvent(window, "cbb.carousel.slideChangeTransitionEnd", {
        swiper,
      });

    // Slider default options
    let sliderOptions = {
      // Optional parameters
      direction: "horizontal",
      loop: false,
      grabCursor: true,
      pagination: true,
      navigation: false,
      scrollbar: false,

      // Slides per view
      slidesPerView: 1,
      slidesPerGroup: 1,
      spaceBetween: 0,
      watchSlidesProgress: true,
      on: {
        afterInit(swiper) {
          triggerEvent(window, "cbb.carousel.afterInit", { swiper });
        },
        slideChangeTransitionStart: slideChangeStart,
        slideChangeTransitionEnd: slideChangeEnd,
        slideResetTransitionStart: slideChangeStart,
        slideResetTransitionEnd: slideChangeEnd,
      },
    };

    // Parse settings from attribute
    const carouselSettings = this.datasetElement.dataset?.carouselSettings;
    const attributeOptions = parseJSON(carouselSettings);

    // Merge with dataset attribute
    sliderOptions = deepMerge(sliderOptions, attributeOptions);

    // Merge with options
    if (options) {
      sliderOptions = deepMerge(sliderOptions, options);
    }

    // Get slider options
    return sliderOptions;
  }

  init() {
    if (this.cbbCarouselId) {
      this.restoreSlider();
      return;
    }

    // Setup the slider.
    this.buildSlider();
  }

  buildSlider() {
    const { sliderElement, sliderOptions } = this;
    const {
      itemSelector,
      itemClass,
      wrapperSelector,
      wrapperClass,
      containerClass,
      preloadClass,
      instanceId,
    } = this.settings;

    // Query slide items
    const sliderItems = Array.from(
      sliderElement.querySelectorAll(itemSelector),
    );

    // Cache it
    this.sliderItems = sliderItems;

    // Add item class
    sliderItems.forEach((item) => this.addClass(item, itemClass));

    // The wrapper element
    let sliderWrapper = sliderElement.querySelector(wrapperSelector);

    if (sliderWrapper) {
      this.hasSlideWrapper = true;
    } else {
      this.hasSlideWrapper = false;

      // Create wrapper element
      sliderWrapper = this.document.createElement("div");
    }

    // Cache it
    this.sliderWrapper = sliderWrapper;

    // Add swiper class
    this.addClass(sliderWrapper, wrapperClass);

    const {
      equalHeight,
      effect,
      centeredSlides,
      centeredSlidesSettings = {},
    } = sliderOptions;

    // Make all items have equal height
    if (equalHeight) {
      this.addClass(sliderWrapper, "is-equal-height");
    }

    // Get slider style and add custom variables
    const sliderStyle = this.getSliderStyle();

    // centeredSlides
    if (
      effect === "slide" &&
      centeredSlides &&
      centeredSlidesSettings?.enable
    ) {
      let inactiveSize = parseFloat(centeredSlidesSettings?.inactiveSize);

      if (!isNaN(inactiveSize)) {
        this.addClass(sliderWrapper, "centered-active-slide");
        sliderStyle.add("--swiper-inactive-scale", inactiveSize);
      }
    }

    if (!this.hasSlideWrapper) {
      // Attach items
      sliderWrapper.append(...sliderItems);
    }

    // Create the container
    const sliderContainer = Object.assign(this.document.createElement("div"), {
      className: containerClass,
    });

    // Cache it
    this.sliderContainer = sliderContainer;

    // Wrap the slider wrapper inside a container
    sliderContainer.appendChild(sliderWrapper);
    sliderElement.appendChild(sliderContainer);

    // Build navigation
    this.buildNavigation();

    // Build play/pause
    this.buildPlayPause();

    // Build pagination
    this.buildPagination();

    // Build scrollbar
    this.buildScrollbar();

    // Mark it as initialized.
    this.addClass(sliderElement, "slider-initialized");

    // Remove the preload class
    this.removeClass(sliderElement, preloadClass);

    // Apply style for all custom properties from sub build functions
    sliderStyle.apply();

    // Initialize the slider.
    this.slider = new Swiper(sliderContainer, sliderOptions);

    // Save the instance to the element.
    sliderElement.setAttribute("data-cbb-carousel-id", instanceId);
  }

  restoreSlider() {
    const swiperElement = this._element.querySelector(
      `.${this.settings.containerClass}`,
    );

    if (!swiperElement) {
      this.buildSlider();

      return;
    }

    /**
     * Reconnect existing controls
     */
    const { cbbCarouselId } = this;
    const sliderOptions = { ...this.sliderOptions };

    // Navigation
    if (sliderOptions.navigation) {
      sliderOptions.navigation = {
        ...sliderOptions.navigationSettings,
        nextEl: this.document.getElementById(
          `${cbbCarouselId}-navigation-next`,
        ),
        prevEl: this.document.getElementById(
          `${cbbCarouselId}-navigation-prev`,
        ),
      };
    }

    // Pagination
    if (sliderOptions.pagination) {
      sliderOptions.pagination = this.buildPaginationOptions({
        ...sliderOptions.paginationSettings,
        el: this.document.getElementById(`${cbbCarouselId}-pagination`),
      });
    }

    // Scrollbar
    if (sliderOptions.scrollbar) {
      sliderOptions.scrollbar = {
        ...sliderOptions.scrollbarSettings,
        el: this.document.getElementById(`${cbbCarouselId}-scrollbar`),
      };
    }

    //  Reconnect play/pause
    if (sliderOptions?.playPause?.enable) {
      this.sliderPlayPause = this.document.getElementById(
        `${cbbCarouselId}-play-pause`,
      );

      if (this.sliderPlayPause) {
        // Bind events
        this.bindPlayPause(this.sliderPlayPause);
      }
    }

    // Recreate swiper instance only
    this.slider = new Swiper(swiperElement, sliderOptions);
  }

  dispose() {
    super.dispose();

    if (this.slider) {
      // Swiper's destroy
      this.slider.destroy();

      // Remove the instance
      this.slider = null;

      if (!this.settings?.isClone) {
        // Restore the original source
        this.sliderElement.replaceWith(this.originalSource);
      }
    }
  }

  /**
   * Build slider controls
   */
  buildSliderControls() {
    if (!this.sliderControls) {
      // Create the control wrapper
      const sliderControls = this.document.createElement("div");

      // Add id
      sliderControls.setAttribute("id", `${this.settings.instanceId}-controls`);

      // Add class
      sliderControls.classList.add("cbb-carousel-controls");

      // Cache it
      this.sliderControls = sliderControls;

      // Add the controls to the slider element
      this.sliderElement.appendChild(sliderControls);
    }

    return this.sliderControls;
  }

  hasCarouselControls(controlType = "") {
    const {
      pagination,
      paginationSettings,
      direction,
      navigation,
      navigationSettings = {},
      playPause = {},
    } = this.sliderOptions;

    if (!pagination || direction !== "horizontal") {
      return false;
    }

    const withPagination = "with-pagination";
    const hasNavigation =
      navigation && navigationSettings?.position === withPagination;
    const hasPlayPause =
      playPause?.enable && playPause?.position === withPagination;

    if (!controlType) {
      return !!(paginationSettings?.position || hasNavigation || hasPlayPause);
    } else {
      if (controlType === "navigation") {
        return hasNavigation;
      } else if (controlType === "playPause") {
        return hasPlayPause;
      }
    }
  }

  getSliderControls(controlType) {
    if (this.hasCarouselControls(controlType)) {
      return this.buildSliderControls();
    }

    return this.sliderElement;
  }

  /**
   * Build pagination
   */
  buildPagination() {
    if (this.sliderOptions.pagination) {
      const sliderControls = this.getSliderControls();
      const {
        sliderElement,
        sliderOptions,
        settings: { instanceId, paginationClass } = {},
      } = this;

      // Create pagination wrapper
      const sliderPagination = this.document.createElement("div");

      // Cache it
      this.sliderPagination = sliderPagination;

      // Add id
      sliderPagination.setAttribute("id", `${instanceId}-pagination`);

      // Add class
      sliderPagination.classList.add(paginationClass);

      const { direction, paginationSettings = {} } = sliderOptions;

      const {
        position,
        xOffset,
        type = "bullets",
        size, // Deprecated
        bulletWidth = size,
        bulletHeight = size,
        activeBulletWidth,
        activeBulletHeight,
        spacing,
        color,
        inactiveColor,
        opacity,
        borderColor,
        fractionColor,
        horizontalGap,
        dynamicBullets = false,
      } = paginationSettings;

      // Get slider style and add custom variables, apply in the buildSlider
      const sliderStyle = this.getSliderStyle();

      if (position && direction === "horizontal") {
        (this.hasCarouselControls()
          ? this.sliderControls
          : sliderPagination
        ).classList.add("pag-custom-position", `pag-is-${position}`);

        sliderStyle.add("--cbb--pag-x-offset", xOffset);
      }

      if (type === "bullets") {
        if (bulletWidth === bulletHeight) {
          sliderStyle.add("--swiper-pagination-bullet-size", bulletWidth);
        } else {
          sliderStyle.add("--swiper-pagination-bullet-width", bulletWidth);
          sliderStyle.add("--swiper-pagination-bullet-height", bulletHeight);
        }

        if (activeBulletWidth) {
          this.sliderPagination.classList.add("active-bullet-width");

          sliderStyle.add(
            "--swiper-pagination-active-bullet-width",
            activeBulletWidth,
          );
        }

        if (activeBulletHeight) {
          this.sliderPagination.classList.add("active-bullet-height");

          sliderStyle.add(
            "--swiper-pagination-active-bullet-height",
            activeBulletHeight,
          );
        }

        sliderStyle.addColor("--swiper-pagination-color", color);
        sliderStyle.addColor(
          "--swiper-pagination-bullet-inactive-color",
          inactiveColor,
        );
        sliderStyle.addColor("--swiper-pagination-bullet-b-color", borderColor);

        sliderStyle.add("--swiper-pagination-bullet-inactive-opacity", opacity);
      } else {
        sliderStyle.addColor(
          "--swiper-pagination-fraction-color",
          fractionColor,
        );
      }

      if (spacing) {
        const offsetProperty =
          direction === "vertical"
            ? "--swiper-pagination-right"
            : "--swiper-pagination-bottom";
        sliderStyle.add(offsetProperty, spacing);
      }

      sliderStyle.add(
        "--swiper-pagination-bullet-horizontal-gap",
        horizontalGap,
      );

      // Add pagination to the options
      this.sliderOptions.pagination = this.buildPaginationOptions({
        el: sliderPagination,
        type,
        dynamicBullets,
      });

      // Add the pagination to the slider element
      sliderControls.appendChild(sliderPagination);
    }
  }

  /**
   * Build pagination arguments
   *
   * @param {Object} options
   * @returns
   */
  buildPaginationOptions(options) {
    return {
      ...options,
      renderBullet(i) {
        return `<span class="swiper-pagination-bullet" tabindex="0" role="button" aria-label="Go to slide ${
          i + 1
        }"><span class="swiper-pagination-bullet__dot"></span></span>`;
      },
      clickable: true,
    };
  }

  /**
   * Build navigation
   */
  buildNavigation() {
    if (this.sliderOptions.navigation) {
      const {
        sliderElement,
        settings: { instanceId, navigationNextClass, navigationPrevClass } = {},
      } = this;

      const {
        nextIcon = {},
        prevIcon = {},
        size,
        position,
        xOffset,
        yOffset,
        spacing,
        color,
        ...otherProps
      } = this.sliderOptions.navigationSettings;

      const sliderControls = this.getSliderControls("navigation");

      // Create naviation next button
      const sliderNavigationNext = this.document.createElement("div");

      // Cache it
      this.sliderNavigationNext = sliderNavigationNext;

      // Add id
      sliderNavigationNext.setAttribute("id", `${instanceId}-navigation-next`);

      // Add class
      sliderNavigationNext.classList.add(navigationNextClass);

      if (nextIcon?.value) {
        sliderNavigationNext.classList.add("has-custom-icon");
        sliderNavigationNext.insertAdjacentHTML("afterbegin", nextIcon.value);
      }

      // Create naviation prev button
      const sliderNavigationPrev = this.document.createElement("div");

      // Cache it
      this.sliderNavigationPrev = sliderNavigationPrev;

      // Add id
      sliderNavigationPrev.setAttribute("id", `${instanceId}-navigation-prev`);

      // Add class
      sliderNavigationPrev.classList.add(navigationPrevClass);

      if (prevIcon?.value) {
        sliderNavigationPrev.classList.add("has-custom-icon");
        sliderNavigationPrev.insertAdjacentHTML("afterbegin", prevIcon.value);
      }

      // Get slider style and add custom variables, apply in the buildSlider
      const sliderStyle = this.getSliderStyle();

      sliderStyle.add("--swiper-navigation-size", size);

      // Add position settings
      if (position) {
        sliderNavigationNext.classList.add(
          "nav-custom-position",
          `is-${position}`,
        );
        sliderNavigationPrev.classList.add(
          "nav-custom-position",
          `is-${position}`,
        );

        sliderStyle.add("--cbb--nav-x-offset", xOffset);
        sliderStyle.add("--cbb--nav-y-offset", yOffset);
      } else {
        sliderStyle.add("--swiper-navigation-sides-offset", spacing);
      }

      sliderStyle.addColor("--swiper-navigation-color", color);

      // Add navigation to the options
      this.sliderOptions.navigation = {
        ...otherProps,
        nextEl: sliderNavigationNext,
        prevEl: sliderNavigationPrev,
      };

      // Add the naviation button to the slider element
      sliderControls.appendChild(sliderNavigationNext);

      // Add the naviation button to the slider element
      sliderControls.appendChild(sliderNavigationPrev);

      // Add class to mark the slider have navigation buttons
      sliderElement.classList.add("swiper--has-navigation");
    }
  }

  /**
   * Build play/pause
   */
  buildPlayPause() {
    const { playPause = {} } = this.sliderOptions;
    if (playPause?.enable) {
      const {
        size,
        position = "bottom-right",
        xOffset,
        yOffset,
        color,
        trackColor,
        progressColor,
      } = playPause;

      const sliderControls = this.getSliderControls("playPause");

      // Create play/pause button
      const sliderPlayPause = this.document.createElement("div");

      // Set the markup
      sliderPlayPause.innerHTML =
        '<svg viewBox="0 0 48 48"><circle class="track" cx="24" cy="24" r="20"></circle><circle cx="24" cy="24" r="20"></circle></svg>';

      // Add attributes
      sliderPlayPause.setAttribute(
        "id",
        `${this.settings.instanceId}-play-pause`,
      );
      sliderPlayPause.setAttribute("tabindex", 0);
      sliderPlayPause.setAttribute("role", "button");

      // Add class
      sliderPlayPause.classList.add(
        "cbb-play-pause",
        "cbb-carousel-play-pause",
        `is-${position}`,
      );

      // Get style builder for PlayPause
      const sliderPPStyle = createStyleManager(sliderPlayPause);

      // Inject custom properties
      sliderPPStyle.add("--cbb--pp-size", size);
      sliderPPStyle.add("--cbb--pp-x-offset", xOffset);
      sliderPPStyle.add("--cbb--pp-y-offset", yOffset);

      sliderPPStyle.addColor("--cbb--pp-color", color);
      sliderPPStyle.addColor("--cbb--progress-track-color", trackColor);
      sliderPPStyle.addColor("--cbb--progress-color", progressColor);

      // Apply here
      sliderPPStyle.apply();

      // Bind events
      this.bindPlayPause(sliderPlayPause);

      // Cache it
      this.sliderPlayPause = sliderPlayPause;

      // Add the play/pause button to the slider element
      sliderControls.appendChild(sliderPlayPause);
    }
  }

  bindPlayPause(sliderPlayPause) {
    const { autoplay, on = {} } = this.sliderOptions;
    const updatePlayPause = (sliderPlayPause, autoplay) => {
      sliderPlayPause.setAttribute(
        "aria-pressed",
        !autoplay ? "true" : "false",
      );
      sliderPlayPause.classList.toggle("is-playing", autoplay);
      sliderPlayPause.classList.toggle("is-paused", !autoplay);
      sliderPlayPause.setAttribute("aria-label", autoplay ? "Pause" : "Play");
    };
    const setProgress = (progress) =>
      sliderPlayPause.style.setProperty("--cbb--progress", progress.toFixed(5));

    const handlePlayPause = () => {
      const { running, start, resume, pause } = this.slider.autoplay;
      if (!running) {
        start();
        resume();
        updatePlayPause(sliderPlayPause, true);
        this.autoplaying = true;
      } else {
        if (!this.autoplaying) {
          resume();
        } else {
          pause();
        }
        this.autoplaying = !this.autoplaying;
        updatePlayPause(sliderPlayPause, this.autoplaying);
      }
    };

    // Add event listener
    sliderPlayPause.addEventListener("click", handlePlayPause);
    sliderPlayPause.addEventListener("keydown", (e) => {
      if (!["Enter", " ", "Spacebar"].includes(e.key)) return;
      e.preventDefault();
      handlePlayPause();
    });

    // Play by default
    this.autoplaying = !!autoplay;
    updatePlayPause(sliderPlayPause, !!autoplay);

    // Set aria-controls
    on.afterInit = compose(on.afterInit, (swiper) => {
      sliderPlayPause.setAttribute(
        "aria-controls",
        swiper.wrapperEl.getAttribute("id"),
      );
    });

    on.autoplayStop = () => {
      updatePlayPause(sliderPlayPause, false);
      setProgress(0);
    };
    on.autoplayResume = () => updatePlayPause(sliderPlayPause, true);
    on.slideChange = compose(on.slideChange, (s) => {
      if (!this.autoplaying) {
        s.autoplay.stop();
      }
    });
    on.lock = (s) => sliderPlayPause.classList.add("swiper-button-lock");
    on.unlock = (s) => sliderPlayPause.classList.remove("swiper-button-lock");
    on.autoplayTimeLeft = (s, time, progress) => {
      if (s.isLocked || s.autoplay.paused) {
        return;
      }

      const activeSlideEl = s.slides[s.activeIndex];
      const currentSlideDelay = parseInt(
        activeSlideEl.getAttribute("data-swiper-autoplay"),
        10,
      );

      setProgress(
        1 - (currentSlideDelay > 0 ? time / currentSlideDelay : progress),
      );
    };

    // Set on back to the options
    this.sliderOptions.on = on;
  }

  /**
   * Build scrollbar
   */
  buildScrollbar() {
    if (this.sliderOptions.scrollbar) {
      const { sliderElement, settings: { instanceId, scrollbarClass } = {} } =
        this;

      // Create scrollbar element
      const sliderScrollbar = this.document.createElement("div");

      // Cache it
      this.sliderScrollbar = sliderScrollbar;

      // Add id
      sliderScrollbar.setAttribute("id", `${instanceId}-scrollbar`);

      // Add class
      sliderScrollbar.classList.add(scrollbarClass);

      const { direction, scrollbarSettings = {} } = this.sliderOptions;
      const {
        trackSize,
        spacing,
        trackColor,
        sliderColor,
        trackOpacity,
        ...otherProps
      } = scrollbarSettings;

      // Get slider style and add custom variables, apply in the buildSlider
      const sliderStyle = this.getSliderStyle();

      sliderStyle.add("--swiper-scrollbar-size", trackSize);

      if (spacing) {
        const offsetProperty =
          direction === "vertical"
            ? "--swiper-scrollbar-right"
            : "--swiper-scrollbar-bottom";
        sliderStyle.add(offsetProperty, spacing);
      }

      sliderStyle.addColor("--swiper-scrollbar-track-color", trackColor);
      sliderStyle.addColor("--swiper-scrollbar-slider-color", sliderColor);
      sliderStyle.add("--swiper-scrollbar-track-opacity", trackOpacity);

      // Add scrollbar to the options
      this.sliderOptions.scrollbar = {
        ...otherProps,
        el: sliderScrollbar,
      };

      // Add the scrollbar to the slider element
      this.sliderContainer.appendChild(sliderScrollbar);
    }
  }

  getSliderStyle() {
    if (!this.sliderStyle) {
      this.sliderStyle = createStyleManager(this.sliderElement);
    }

    return this.sliderStyle;
  }

  addClass(element, classname) {
    if (!element.classList.contains(classname)) {
      element.classList.add(classname);
    }
  }

  removeClass(element, classname) {
    if (classname) {
      element.classList.remove(classname);
    }
  }
}

/**
 * Get carousel manager object
 *
 * @returns {Array}
 */
export const getCarouselManager = () => {
  if (!window?.CBBCarousels) {
    window.CBBCarousels = {};
  }

  return window.CBBCarousels;
};

export const addCarousel = (element, args, carouselElements = []) => {
  const manager = getCarouselManager();
  const { instanceId } = args;
  if (!manager[instanceId] || !manager[instanceId]?.slider) {
    if (carouselElements.length > 1) {
      const thumbs = buildThumbs(element, carouselElements);
      if (thumbs) {
        args.sliderOptions = { thumbs: { swiper: thumbs.slider } };
      }
    }

    if (element.classList.contains("wp-block-query")) {
      args.wrapperSelector = "ul";
      args.itemSelector = "li";
    }

    const instance = new CarouselScript(element, args);
    manager[instance?.cbbCarouselId || instanceId] = instance;

    return instance;
  }

  return manager[instanceId];
};

const buildThumbs = (element, carouselElements) => {
  let carouselSettings = element?.dataset?.carouselSettings;
  if (!carouselSettings) {
    return null;
  }

  carouselSettings = parseJSON(carouselSettings);

  const thumbSelector = carouselSettings?.thumbsSettings?.enable
    ? carouselSettings.thumbsSettings?.selector
    : "";

  if (!thumbSelector) {
    return null;
  }

  const thumbElement = element.ownerDocument.querySelector(thumbSelector);
  if (!thumbElement) {
    return null;
  }

  const thumbsIndex = carouselElements.findIndex((element) =>
    element.isSameNode(thumbElement),
  );

  if (thumbsIndex === -1) {
    return null;
  }

  return addCarousel(
    thumbElement,
    {
      instanceId: `cbb-carousel-${thumbsIndex + 1}`,
    },
    carouselElements,
  );
};

exposeComponent("CarouselScript", CarouselScript);

export default CarouselScript;

```
