<commit_before>import {
  renameKey,
  props,
  define,
  hasNativeShadowDomSupport,
} from '@bolt/core/utils';
import { html, withLitHtml } from '@bolt/core/renderers/renderer-lit-html';
import classNames from 'classnames/bind';
import changeCase from 'change-case';
import Swiper from 'swiper';
import styles from '../index.scss';
import originalSchema from '../carousel.schema.yml';

let cx = classNames.bind(styles);
let wasCarouselResizerAdded = false;

function addBoltCarouselResizer() {
  if (wasCarouselResizerAdded === false) {
    wasCarouselResizerAdded = true;

    // Create a custom 'optimizedResize' event that works just like window.resize but is more performant because it
    // won't fire before a previous event is complete.
    // This was adapted from https://developer.mozilla.org/en-US/docs/Web/Events/resize
    (function() {
      function throttle(type, name, obj) {
        obj = obj || window;
        let running = false;

        function func() {
          if (running) {
            return;
          }
          running = true;
          requestAnimationFrame(function() {
            obj.dispatchEvent(new CustomEvent(name));
            running = false;
          });
        }
        obj.addEventListener(type, func);
      }

      // Initialize on window.resize event.  Note that throttle can also be initialized on any type of event,
      // such as scroll.
      throttle('resize', 'carousel:resize');
    })();
  } else {
    // console.log('carouselResizer already Added');
  }
}

// @todo: re-wire to point to actual breakpoint data
const boltBreakpoints = {
  xxsmall: '320px',
  xsmall: '400px',
  small: '600px',
  medium: '800px',
  large: '1000px',
  xlarge: '1200px',
  xxlarge: '1400px',
  xxxlarge: '1920px',
};

const carouselProps = {};
const schemaPropKeys = Object.keys(originalSchema.properties);

function setWebComponentProperty(propertyName, propertyType, property) {
  return {
    ...props[propertyType],
    // Set to '', not null, or validator will not delete empty props
    ...{ default: property.default ? property.default : '' },
  };
}

for (const key of schemaPropKeys) {
  const property = originalSchema.properties[key];
  const propertyName = changeCase.camelCase(key);
  const propertyType =
    typeof property.type === 'object' && property.type.length > 1
      ? 'string'
      : property.type === 'integer'
      ? 'number'
      : property.type;
  carouselProps[propertyName] = setWebComponentProperty(
    propertyName,
    propertyType,
    property,
  );
}

@define
class BoltCarousel extends withLitHtml() {
  static is = 'bolt-carousel';

  static props = {
    ...carouselProps,
    slideOffsetBefore: props.boolean,
    slideOffsetAfter: props.boolean,
    thumbs: {
      ...props.object,
      ...{ default: false },
    },
  };

  // https://github.com/WebReflection/document-register-element#upgrading-the-constructor-context
  constructor(self) {
    self = super(self);
    self.useShadow = false;
    self.schema = originalSchema;
    self.onSlideChange = self.onSlideChange.bind(self);
    self.hideArrowsIfAllSlidesAreVisible = self.hideArrowsIfAllSlidesAreVisible.bind(
      self,
    );
    self.disableSwipingIfAllSlidesAreVisible = self.disableSwipingIfAllSlidesAreVisible.bind(
      self,
    );
    self.conditionallyDisableButtons = self.conditionallyDisableButtons.bind(
      self,
    );
    self.reInitCarousel = self.reInitCarousel.bind(self);
    return self;
  }

  checkForSlideOffset() {
    const carouselSlides = this.querySelectorAll('bolt-carousel-slide');
    this.slideOffsetBefore = carouselSlides[0].querySelector('bolt-card')
      ? true
      : false;
    this.slideOffsetAfter = carouselSlides[
      carouselSlides.length - 1
    ].querySelector('bolt-card')
      ? true
      : false;
  }

  connecting() {
    super.connecting && super.connecting();
    addBoltCarouselResizer();
    window.addEventListener('carousel:resize', this.reInitCarousel);

    const nextButton = this.querySelector('[slot="next-btn"]');
    const prevButton = this.querySelector('[slot="previous-btn"]');

    if (nextButton) {
      nextButton.setAttribute('tabindex', '-1');
    }

    if (prevButton) {
      prevButton.setAttribute('tabindex', '-1');
    }

    this.checkForSlideOffset();
  }

  // recalculates the ideal # of slides to display when the overal carousel width changes
  // @todo: update to only reinitialize when the data for this changes
  reInitCarousel() {
    this.options.slidesPerView = this.calculateSlidesPerView(
      this.props.slidesPerView,
    );
    this.calculateSlidesPerViewBreakpoints();

    // track the currently active slide so the new swiper instance
    const currentlyActiveSlide = this.swiper.activeIndex;
    this.options.initialSlide = currentlyActiveSlide;

    this.swiper.destroy(false, true);
    this.options.thumbs = this.props.thumbs;

    this.swiper = new Swiper(
      this.renderRoot.querySelector('.c-bolt-carousel'),
      {
        ...this.options,
      },
    );
  }

  findIdealNumberOfSlides(desiredNumberOfSlides) {
    const availableWidth = this.getBoundingClientRect().width;
    const spaceBetween = this.spaceBetweenConfig;
    const minWidth = this.props.noMinWidth ? 0 : 240; // @todo: update to pull in this min-width automatically<commit_msg>feat: only re-initialize carousel if slidesPerView changes<commit_after>import {
  renameKey,
  props,
  define,
  hasNativeShadowDomSupport,
} from '@bolt/core/utils';
import { html, withLitHtml } from '@bolt/core/renderers/renderer-lit-html';
import classNames from 'classnames/bind';
import changeCase from 'change-case';
import Swiper from 'swiper';
import styles from '../index.scss';
import originalSchema from '../carousel.schema.yml';

let cx = classNames.bind(styles);
let wasCarouselResizerAdded = false;

function addBoltCarouselResizer() {
  if (wasCarouselResizerAdded === false) {
    wasCarouselResizerAdded = true;

    // Create a custom 'optimizedResize' event that works just like window.resize but is more performant because it
    // won't fire before a previous event is complete.
    // This was adapted from https://developer.mozilla.org/en-US/docs/Web/Events/resize
    (function() {
      function throttle(type, name, obj) {
        obj = obj || window;
        let running = false;

        function func() {
          if (running) {
            return;
          }
          running = true;
          requestAnimationFrame(function() {
            obj.dispatchEvent(new CustomEvent(name));
            running = false;
          });
        }
        obj.addEventListener(type, func);
      }

      // Initialize on window.resize event.  Note that throttle can also be initialized on any type of event,
      // such as scroll.
      throttle('resize', 'carousel:resize');
    })();
  } else {
    // console.log('carouselResizer already Added');
  }
}

// @todo: re-wire to point to actual breakpoint data
const boltBreakpoints = {
  xxsmall: '320px',
  xsmall: '400px',
  small: '600px',
  medium: '800px',
  large: '1000px',
  xlarge: '1200px',
  xxlarge: '1400px',
  xxxlarge: '1920px',
};

const carouselProps = {};
const schemaPropKeys = Object.keys(originalSchema.properties);

function setWebComponentProperty(propertyName, propertyType, property) {
  return {
    ...props[propertyType],
    // Set to '', not null, or validator will not delete empty props
    ...{ default: property.default ? property.default : '' },
  };
}

for (const key of schemaPropKeys) {
  const property = originalSchema.properties[key];
  const propertyName = changeCase.camelCase(key);
  const propertyType =
    typeof property.type === 'object' && property.type.length > 1
      ? 'string'
      : property.type === 'integer'
      ? 'number'
      : property.type;
  carouselProps[propertyName] = setWebComponentProperty(
    propertyName,
    propertyType,
    property,
  );
}

@define
class BoltCarousel extends withLitHtml() {
  static is = 'bolt-carousel';

  static props = {
    ...carouselProps,
    slideOffsetBefore: props.boolean,
    slideOffsetAfter: props.boolean,
    thumbs: {
      ...props.object,
      ...{ default: false },
    },
  };

  // https://github.com/WebReflection/document-register-element#upgrading-the-constructor-context
  constructor(self) {
    self = super(self);
    self.useShadow = false;
    self.schema = originalSchema;
    self.onSlideChange = self.onSlideChange.bind(self);
    self.hideArrowsIfAllSlidesAreVisible = self.hideArrowsIfAllSlidesAreVisible.bind(
      self,
    );
    self.disableSwipingIfAllSlidesAreVisible = self.disableSwipingIfAllSlidesAreVisible.bind(
      self,
    );
    self.conditionallyDisableButtons = self.conditionallyDisableButtons.bind(
      self,
    );
    self.reInitCarousel = self.reInitCarousel.bind(self);
    return self;
  }

  checkForSlideOffset() {
    const carouselSlides = this.querySelectorAll('bolt-carousel-slide');
    this.slideOffsetBefore = carouselSlides[0].querySelector('bolt-card')
      ? true
      : false;
    this.slideOffsetAfter = carouselSlides[
      carouselSlides.length - 1
    ].querySelector('bolt-card')
      ? true
      : false;
  }

  connecting() {
    super.connecting && super.connecting();
    addBoltCarouselResizer();
    window.addEventListener('carousel:resize', this.reInitCarousel);

    const nextButton = this.querySelector('[slot="next-btn"]');
    const prevButton = this.querySelector('[slot="previous-btn"]');

    if (nextButton) {
      nextButton.setAttribute('tabindex', '-1');
    }

    if (prevButton) {
      prevButton.setAttribute('tabindex', '-1');
    }

    this.checkForSlideOffset();
  }

  // recalculates the ideal # of slides to display when the overal carousel width changes
  // @todo: update to only reinitialize when the data for this changes
  reInitCarousel() {
    const calculatedSlidesPerView = this.calculateSlidesPerView(
      this.props.slidesPerView,
    );

    // Only re-initialize if slidesPerView changes
    if (this.options.slidesPerView === calculatedSlidesPerView) {
      this.swiper.update();
    } else {
      this.options.slidesPerView = calculatedSlidesPerView;

      this.calculateSlidesPerViewBreakpoints();

      // track the currently active slide so the new swiper instance
      const currentlyActiveSlide = this.swiper.activeIndex;
      this.options.initialSlide = currentlyActiveSlide;

      this.swiper.destroy(false, true);
      this.options.thumbs = this.props.thumbs;

      this.swiper = new Swiper(
        this.renderRoot.querySelector('.c-bolt-carousel'),
        {
          ...this.options,
        },
      );
    }
  }

  findIdealNumberOfSlides(desiredNumberOfSlides) {
    const availableWidth = this.getBoundingClientRect().width;
    const spaceBetween = this.spaceBetweenConfig;
    const minWidth = this.props.noMinWidth ? 0 : 240; // @todo: update to pull in this min-width automatically
{'fraction_non_alphanumeric': 0.11728733114275283, 'fraction_numerical': 0.006754289886820007, 'mean_word_length': 3.148807269973495, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5994101', 'n_tokens_mistral': 3339, 'n_tokens_neox': 3230, 'n_words': 726}