'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

const index = require('./index-58ea899e.js');
const synchronizeTaskQueue = require('./synchronize-task-queue-1ee80e94.js');
const accessibility = require('./accessibility-bfa227f6.js');
const component = require('./component-1e352960.js');
const effect = require('./effect-98e88068.js');
const responsiveFormatFacade = require('./responsive-format-facade-2cab7344.js');
const globalSlimmerRegistry = require('./global-slimmer-registry-b3bce7e0.js');
const componentUsageRuntimeMetrics = require('./component-usage-runtime-metrics-4572c5b7.js');
const pageResizeObserverSlimmer = require('./page-resize-observer-slimmer-273d62ef.js');
const eventEmitSlimmer = require('./event-emit-slimmer-bcb458b2.js');
const vegaEventId = require('./vega-event-id-c08ce3d3.js');
const deprecatedPropertySlimmer = require('./deprecated-property-slimmer-300a3929.js');
const tryGetDocument = require('./try-get-document-c0ebd39a.js');
require('./type-guard-3ec852d7.js');
require('./breakpoints-ebde4837.js');
require('./ui-32120990.js');
require('./typography-4560e7f1.js');
require('./internal-translation-controller-fb1532f4.js');
require('./change-manager-a297e4d2.js');
require('./static-subject-title-5829a298.js');
require('./breakpoints-1cc2c4c6.js');
require('./number-4816603d.js');
require('./pixel-98f2a10c.js');
require('./array-249289f2.js');
require('./feature-flag-controller-9129ef52.js');
require('./index-f054eb5d.js');
require('./dynamic-slimmer-f31fdfd7.js');
require('./dom-node-subject-observer-factory-9110cb94.js');
require('./observer-f49483e8.js');
require('./ui-ae4ee13d.js');
require('./internal-vega-event-manager-fef893bf.js');
require('./object-b53e9416.js');

var TouchDirection;
(function (TouchDirection) {
  TouchDirection["RIGHT"] = "TOUCH_DIR_RIGHT";
  TouchDirection["LEFT"] = "TOUCH_DIR_LEFT";
  TouchDirection["UP"] = "TOUCH_DIR_UP";
  TouchDirection["DOWN"] = "TOUCH_DIR_DOWN";
})(TouchDirection || (TouchDirection = {}));
/**
 * The TouchListener class is a class that listens for touch events on a touchable element
 * and calls a callback function when a touch event occurs
 *
 * @property {TouchListenerInitParams} TouchListenerInitParams params for create touch listener
 * @property {{ x: number; y: number }} touchStartState state object to record start touch coordinate
 */
class TouchListener {
  /**
   * Create a new instance of the TouchListener class
   *
   * @param {TouchListenerInitParams} params - TouchListenerInitParams
   */
  constructor(params) {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    this.touchStart = this.onTouchStart.bind(this);
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    this.touchMove = this.onTouchMove.bind(this);
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    this.touchEnd = this.onTouchEnd.bind(this);
    this.touchableParams = params;
    this.attachListeners();
  }
  /**
   * It creates a new instance of the TouchListener class
   *
   * @param {TouchListenerInitParams} params - TouchListenerInitParams
   * @returns {TouchListener} A new instance of the TouchListener class.
   */
  static init(params) {
    return new TouchListener(params);
  }
  /**
   * Given the start and end coordinates of a touch event, return the direction and distance of the touch
   *
   * @param {number} startX - The x coordinate of the touch start event.
   * @param {number} startY - The y-coordinate of the touch start event.
   * @param {number} endX - The x coordinate of the touch end event.
   * @param {number} endY - the y coordinate of the touch event.
   * @returns {TouchDirectionAndDistanceType} The direction and distance of the touch.
   */
  static getTouchDirectionAndDistance(startX, startY, endX, endY) {
    const delX = endX - startX;
    const delY = endY - startY;
    if (Math.abs(delX) > Math.abs(delY)) {
      return {
        direction: delX > 0 ? TouchDirection.RIGHT : TouchDirection.LEFT,
        distance: Math.abs(delX),
      };
    }
    else {
      return {
        direction: delY > 0 ? TouchDirection.UP : TouchDirection.DOWN,
        distance: Math.abs(delY),
      };
    }
  }
  /**
   * Get the coordinates of a touch event
   *
   * @param {TouchEvent} event - The event object that was passed to the handler.
   * @returns {TouchEventCoordinatesType} The coordinates of the touch event.
   */
  static getTouchEventCoordinates(event) {
    return { x: event.changedTouches[0].screenX, y: event.changedTouches[0].screenY };
  }
  /**
   * It removes the touchable events from the touchable.
   */
  destroy() {
    this.touchableParams.touchable.removeEventListener('touchstart', this.touchStart);
    this.touchableParams.touchable.removeEventListener('touchmove', this.touchMove);
    this.touchableParams.touchable.removeEventListener('touchend', this.touchEnd);
  }
  /**
   * Attach the touchstart, touchmove, and touchend listeners to the touchable element.
   * The bind() method returns a copy of the given function with the provided this value and initial arguments,
   * which causes remove event listeners to fail.
   */
  attachListeners() {
    this.touchableParams.touchable.addEventListener('touchstart', this.touchStart);
    this.touchableParams.touchable.addEventListener('touchmove', this.touchMove);
    this.touchableParams.touchable.addEventListener('touchend', this.touchEnd);
  }
  /**
   * It prevents the default behavior of the touch event and stores the coordinates of the touch event in the
   * touchStartState variable.
   *
   * @param {TouchEvent} event - The event object that was triggered.
   */
  onTouchStart(event) {
    var _a, _b;
    this.touchStartState = TouchListener.getTouchEventCoordinates(event);
    (_b = (_a = this.touchableParams).onTouchStart) === null || _b === void 0 ? void 0 : _b.call(_a, this.touchStartState.x, this.touchStartState.y);
  }
  /**
   * It prevents the default behavior of the event, and then it gets the coordinates of the touch event, and then it gets
   * the direction and distance of the touch event.
   *
   * @param {TouchEvent} event - The native event object.
   */
  onTouchMove(event) {
    var _a, _b;
    const { x, y } = TouchListener.getTouchEventCoordinates(event);
    const { direction, distance } = TouchListener.getTouchDirectionAndDistance(this.touchStartState.x, this.touchStartState.y, x, y);
    (_b = (_a = this.touchableParams).onTouchMove) === null || _b === void 0 ? void 0 : _b.call(_a, direction, distance);
  }
  /**
   * It calls the onTouchEnd function of the touchableParams object.
   *
   * @param {TouchEvent} event - The event object that was passed to the onTouchStart or onTouchEnd callback.
   */
  onTouchEnd(event) {
    var _a, _b;
    const { x, y } = TouchListener.getTouchEventCoordinates(event);
    const { direction } = TouchListener.getTouchDirectionAndDistance(this.touchStartState.x, this.touchStartState.y, x, y);
    (_b = (_a = this.touchableParams).onTouchEnd) === null || _b === void 0 ? void 0 : _b.call(_a, direction);
    this.resetStartState();
  }
  /**
   * Reset the start state
   */
  resetStartState() {
    this.touchStartState = { x: 0, y: 0 };
  }
}

const VegaCarouselRuntimeMetricsPayloadDefinition = [
  {
    payloadKey: 'PER_PAGE_IS_ONE',
    payloadDescription: '@deprecated Specifies the number of elements displayed per page in the carousel.',
    /**
     * The function checks if the `perPage` property of the `host` element is equal to '1'.
     * If it is, the function will return `true`.
     *
     * @param {HTMLElement} host - The element to check
     * @returns {boolean} A boolean value
     */
    payloadValue: (host) => host.perPage === 1,
  },
  {
    payloadKey: 'PER_PAGE_IS_NOT_ONE',
    payloadDescription: '@deprecated Specifies the number of elements displayed per page in the carousel.',
    /**
     * The function checks if the `perPage` property of the `host` element is not equal to '1'.
     * If it is, the function will return `true`.
     *
     * @param {HTMLElement} host - The element to check
     * @returns {boolean} A boolean value
     */
    payloadValue: (host) => host.perPage !== 1,
  },
];

const vegaCarouselCss = ":host{display:block}:host .vega-carousel-indicators-container{display:flex;justify-content:center;align-items:center;margin-top:24px}:host .vega-carousel-indicators-container>div{border-radius:9999px;width:16px;height:16px;border-width:2px;border-style:solid;margin-right:24px;cursor:pointer;border:2px solid rgba(var(--v-border-secondary-btn, 19, 98, 226, 1))}:host .vega-carousel-indicators-container>div:focus{border:2px solid rgba(var(--v-border-secondary-btn-hover, 4, 112, 236, 1));background-color:rgba(var(--v-bg-quaternary, 241, 248, 251, 1));outline:2px solid rgba(var(--v-border-color-action, 19, 98, 226, 1));outline-offset:2px}:host .vega-carousel-indicators-container>div:hover{border:2px solid rgba(var(--v-border-secondary-btn-hover, 4, 112, 236, 1));background-color:rgba(var(--v-bg-quaternary, 241, 248, 251, 1))}:host .vega-carousel-indicators-container>div.vega-carousel-indicator-active{background-color:rgba(var(--v-bg-action, 19, 98, 226, 1))}:host .vega-carousel-indicators-container>div.vega-carousel-indicator-active:hover{border:2px solid rgba(var(--v-border-secondary-btn, 19, 98, 226, 1))}:host .vega-carousel-indicators-container>div:last-child{margin-right:0px}:host .carousel-inner{position:relative;width:100%;overflow:hidden}:host .carousel-inner.carousel-stop-swipe{pointer-events:none}:host ::slotted(.carousel-item){width:100%;position:relative;display:none;float:left;transition:transform 0.6s ease;margin-right:-100%}:host ::slotted(.carousel-item.active),:host ::slotted(.carousel-item-next),:host ::slotted(.carousel-item-prev){display:block}:host ::slotted(.carousel-item-next:not(.carousel-item-start)),:host ::slotted(.active.carousel-item-end){transform:translateX(100%)}:host ::slotted(.carousel-item-prev:not(.carousel-item-end)),:host ::slotted(.active.carousel-item-start){transform:translateX(-100%)}";

var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
    r = Reflect.decorate(decorators, target, key, desc);
  else
    for (var i = decorators.length - 1; i >= 0; i--)
      if (d = decorators[i])
        r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  return c > 3 && r && Object.defineProperty(target, key, r), r;
};
const VegaCarousel = class {
  constructor(hostRef) {
    index.registerInstance(this, hostRef);
    this.vegaPageUpdate = index.createEvent(this, "vegaPageUpdate", 7);
    this.pageUpdate = index.createEvent(this, "pageUpdate", 7);
    this.globalSlimmers = {};
    this.vegaComponentUsageRuntimeMetricsSlimmer = new componentUsageRuntimeMetrics.VegaComponentUsageRuntimeMetricsSlimmer(VegaCarouselRuntimeMetricsPayloadDefinition);
    this.pageResizeObserverSlimmer = new pageResizeObserverSlimmer.PageResizeObserverSlimmer({
      callback: /* istanbul ignore next */ () => {
        if (this.getCarouselItemsPerPage() !== this.currentItemsPerPage) {
          this.updatePageLayout();
        }
      },
    });
    this.pageUpdateEventEmitter = eventEmitSlimmer.createEventEmitSlimmer(VegaCarousel, vegaEventId.VegaPageUpdate);
    this.deprecatedPropertySlimmer = deprecatedPropertySlimmer.createDeprecatedPropertySlimmer(VegaCarousel, 'itemsPerPage', 'perPage', 1);
    this.carouselContentElements = [];
    this.slideTaskQueue = new synchronizeTaskQueue.SynchronizeTaskQueue();
    this.currentItemsPerPage = 1;
    this.page = 1;
    /**
     * Specifies the number of elements displayed per page in the carousel.
     * @deprecated This property will be removed soon and replaced by prop itemsPerPage
     *
     * @vegaVersion 1.0.2
     */
    this.perPage = 1;
    /**
     * Specifies the number of items displayed per page in the carousel.
     *
     * @vegaVersion 2.1.0
     */
    this.itemsPerPage = 1;
    /**
     * Specifies whether to show the navigational buttons
     *    at the bottom of the carousel.
     *
     * @vegaVersion 1.0.2
     */
    this.showSlider = true;
    /**
     * Controls the amount of space between the elements in the carousel
     *    when more than one element is displayed on each page
     *    using the `itemsPerPage` property.
     *
     * @vegaVersion 1.0.2
     */
    this.spacing = 'size-16';
    /**
     * Indicates whether the carousel can be swiped
     *    to navigate between pages on a mobile device.
     *
     * @vegaVersion 1.18.0
     */
    this.canSwipe = true;
    this.onClickIndicators = async (e) => {
      const target = e.currentTarget;
      const targetPage = Number(target.dataset.page);
      await this.goToPage(targetPage);
    };
    /**
     * Get the total page that will be shown in carousel.
     */
    this.getTotalPage = () => {
      const count = this.carouselContentElements.length;
      return Math.ceil(count / this.currentItemsPerPage);
    };
    this.updatePageLayout = () => {
      this.currentItemsPerPage = this.getCarouselItemsPerPage();
      this.totalPages = this.getTotalPage();
      this.page = 1;
      this.wrapChildContentAsCarouselItem();
    };
    /**
     * The below method is e2e-test covered in
     * @see{module:vega-carousel-call-observe-method}
     */
    /* istanbul ignore next */
    this.initMutationObserver = () => {
      this.mutationObserver = new MutationObserver(async () => {
        await this.updateContentByObserverSlotChange();
      });
      this.mutationObserver.observe(this.host, { childList: true });
    };
    /**
     * The below method is e2e-test covered in
     * @see{module:vega-carousel-with-touch-event}
     */
    /* istanbul ignore next */
    this.initTouchEvent = () => {
      this.touchListener = TouchListener.init({
        touchable: this.listContainer,
        onTouchEnd: async (direction) => {
          const pageDelta = direction === TouchDirection.RIGHT ? -1 : direction === TouchDirection.LEFT ? 1 : 0;
          const nextPage = this.page + pageDelta;
          await this.goToPage(nextPage);
        },
      });
    };
  }
  watchPage() {
    this.pageUpdateEventEmitter.emit(this.page);
  }
  watchPerPage() {
    this.updatePageLayout();
  }
  watchItemsPerPage() {
    this.updatePageLayout();
  }
  onSpacingPropsChange() {
    const carouselItems = this.host.querySelectorAll('vega-grid');
    carouselItems.forEach((item) => {
      item.gap = this.spacing;
    });
  }
  disconnectedCallback() {
    if (this.mutationObserver) {
      this.mutationObserver.disconnect();
    }
    if (this.touchListener) {
      this.touchListener.destroy();
    }
  }
  componentDidLoad() {
    this.carouselContentElements = Array.from(this.host.children);
    this.updatePageLayout();
    this.initMutationObserver();
    this.initTouchEvent();
  }
  /**
   * Invoke this method to transition the carousel to the next available page,
   *    if it exists.
   *
   * @vegaVersion 1.0.2
   */
  async nextPage() {
    const nextPage = this.page < this.totalPages ? this.page + 1 : this.page;
    await this.goToPage(nextPage);
  }
  /**
   * Invoke this method to transition the carousel to the previous page,
   *    if it exists.
   *
   * @vegaVersion 1.0.2
   */
  async prevPage() {
    const nextPage = this.page > 1 ? this.page - 1 : this.page;
    await this.goToPage(nextPage);
  }
  /**
   * Invoke this method to navigate the carousel to the specified page number.
   *
   * @param nextPage
   * @returns {Promise<void>}
   * @vegaVersion 1.0.6
   */
  async goToPage(nextPage) {
    await this.goToPageInternal(nextPage);
  }
  render() {
    return component.sanitizeVegaComponent(index.h(index.Host, null, index.h("div", { class: {
        'carousel-inner': true,
        'carousel-stop-swipe': !this.canSwipe,
      }, ref: (el) => (this.listContainer = el) }, index.h("slot", null)), this.renderIndicatorDom()), this.host);
  }
  /**
   * The function `goToPageInternal` is used to navigate to a specific page in a slideshow, with an optional animation.
   *
   * @param {number} nextPage - The `nextPage` parameter is the page number that you want to navigate to. It should be a number between 1 and the total number of pages (`this.totalPages`).
   * @param {boolean} [needsAnimation=true] - The `needsAnimation` parameter is a boolean value that
   * indicates whether or not the slide animation should be performed when navigating to the next page.
   * If `needsAnimation` is `true`, the slide animation will be performed. If `needsAnimation` is
   * `false`, the slide animation will be disabled
   */
  async goToPageInternal(nextPage, needsAnimation = true) {
    if (nextPage >= 1 && nextPage <= this.totalPages) {
      if (nextPage !== this.page) {
        this.page = nextPage;
        await this.slideTaskQueue.enqueue({
          run: () => {
            return this.doSlide(nextPage, needsAnimation);
          },
        });
      }
    }
  }
  renderIndicatorDom() {
    return (this.showSlider && (index.h("div", { class: "vega-carousel-indicators-container" }, new Array(this.totalPages).fill('').map((_, index$1) => {
      return (index.h("div", { key: index$1, class: {
          'vega-carousel-indicator-active': index$1 + 1 === this.page,
        }, "data-page": index$1 + 1, role: 'button', "aria-label": "No label defined", tabIndex: 0, onKeyDown: accessibility.createEnterKeyHandlerToTriggerClick(), onClick: this.onClickIndicators }));
    }))));
  }
  /**
   * The below method is e2e-test covered in
   * @see{module:vega-carousel-call-observe-method}
   */
  /* istanbul ignore next */
  async updateContentByObserverSlotChange() {
    const initPage = this.page;
    const unManagedContentElements = Array.from(this.host.children).filter((element) => !element.classList.contains('carousel-item'));
    const currentCarouselContentElements = Array.from(this.host.querySelectorAll('.carousel-item vega-grid > div > *'));
    if (currentCarouselContentElements.length !== this.carouselContentElements.length ||
      unManagedContentElements.length > 0) {
      this.carouselContentElements = currentCarouselContentElements.concat(unManagedContentElements);
      this.updatePageLayout();
    }
    await this.goToPageInternal(initPage, false);
  }
  wrapChildContentAsCarouselItem() {
    const carouselItemWrapperList = [];
    const carouselContentElementArray = this.carouselContentElements;
    if (tryGetDocument.tryGetDocument()) {
      for (let j = 0; j < this.totalPages; j++) {
        const carouselItemWrapper = tryGetDocument.tryGetDocument().createElement('vega-grid');
        carouselItemWrapper.setAttribute('gap', this.spacing);
        carouselItemWrapper.setAttribute('column', this.currentItemsPerPage.toString());
        carouselItemWrapper.setAttribute('row', '1');
        for (let i = j * this.currentItemsPerPage; i < carouselContentElementArray.length && i < this.currentItemsPerPage * (j + 1); i++) {
          const divInner = tryGetDocument.tryGetDocument().createElement('div');
          divInner.appendChild(carouselContentElementArray[i]);
          carouselItemWrapper.appendChild(divInner);
        }
        const divOuter = tryGetDocument.tryGetDocument().createElement('div');
        divOuter.classList.add('carousel-item');
        j === 0 && divOuter.classList.add('active');
        divOuter.appendChild(carouselItemWrapper);
        carouselItemWrapperList.push(divOuter);
      }
      this.host.replaceChildren(...carouselItemWrapperList);
    }
  }
  /**
   * 1.make targetItem from translateX(-/+100%) to translateX(0).
   * 2.make activeItem from translateX(0) to translateX(-/+100%).
   * 3.clear up the added class and mark the current visible item as active.
   * The below method is e2e-test covered in
   * @see{module:vega-carousel-do-slide}
   * @see{module:vega-carousel-do-slide-in-order}
   */
  /* istanbul ignore next */
  doSlide(nextPage, needsAnimation) {
    return new Promise((resolve, reject) => {
      const activeItem = this.host.querySelector('.active');
      const isNext = nextPage - 1 > Array.from(this.host.children).indexOf(activeItem);
      const targetItem = this.host.children[nextPage - 1];
      const directionalClassName = isNext ? 'carousel-item-start' : 'carousel-item-end';
      const orderClassName = isNext ? 'carousel-item-next' : 'carousel-item-prev';
      if (activeItem && targetItem) {
        if (needsAnimation) {
          targetItem.classList.add(orderClassName);
          effect.reflow(targetItem);
          targetItem.classList.add(directionalClassName);
          activeItem.classList.add(directionalClassName);
          effect.executeAfterTransition(() => {
            targetItem.classList.remove(directionalClassName, orderClassName);
            activeItem.classList.remove('active', directionalClassName);
            targetItem.classList.add('active');
            resolve();
          }, activeItem, 600);
        }
        else {
          activeItem.classList.remove('active');
          effect.reflow(targetItem);
          targetItem.classList.add('active');
          resolve();
        }
      }
      else {
        reject('Cannot find active and target item in carousel list');
      }
    });
  }
  /**
   * The below method is e2e-test covered in
   * @see{module:vega-carousel-with-screen-switch-mobile}
   */
  /* istanbul ignore next */
  getCarouselItemsPerPage() {
    const itemsPerPage = responsiveFormatFacade.ResponsiveFormatFacade.formatCustom(this.deprecatedPropertySlimmer.getValue());
    if (itemsPerPage) {
      return Math.max(1, Math.min(4, itemsPerPage, this.carouselContentElements.length));
    }
    else {
      return 1;
    }
  }
  get host() { return index.getElement(this); }
  static get watchers() { return {
    "page": ["watchPage"],
    "perPage": ["watchPerPage"],
    "itemsPerPage": ["watchItemsPerPage"],
    "spacing": ["onSpacingPropsChange"]
  }; }
};
__decorate([
  componentUsageRuntimeMetrics.InjectVegaGlobalSlimmer()
], VegaCarousel.prototype, "globalSlimmers", void 0);
__decorate([
  globalSlimmerRegistry.InjectVegaSlimmer()
], VegaCarousel.prototype, "vegaComponentUsageRuntimeMetricsSlimmer", void 0);
__decorate([
  globalSlimmerRegistry.InjectVegaSlimmer()
], VegaCarousel.prototype, "pageResizeObserverSlimmer", void 0);
__decorate([
  globalSlimmerRegistry.InjectVegaSlimmer()
], VegaCarousel.prototype, "pageUpdateEventEmitter", void 0);
__decorate([
  globalSlimmerRegistry.InjectVegaSlimmer()
], VegaCarousel.prototype, "deprecatedPropertySlimmer", void 0);
VegaCarousel.style = vegaCarouselCss;

exports.vega_carousel = VegaCarousel;
