{
  "version": 3,
  "sources": ["/cdn/shop/t/8/assets/scrolling.js?ddd=40726"],
  "sourcesContent": ["import { debounce, throttle, prefersReducedMotion } from '@theme/utilities';\n\n/**\n * Timeout duration (in milliseconds) after which scroll is considered to have ended.\n * @constant {number}\n */\nconst SCROLL_END_TIMEOUT = 50;\n\n/**\n * Class representing a Scroller that handles smooth scrolling and detects scroll end events.\n *\n * @class\n */\nexport class Scroller {\n  /**\n   * The element to apply scrolling to.\n   * @type {HTMLElement}\n   */\n  element;\n\n  /**\n   * Promise that resolves when scrolling ends.\n   * @type {Promise<void>|undefined}\n   */\n  #promise = undefined;\n\n  /**\n   * Function to resolve the scroll end promise.\n   * @type {Function|undefined}\n   */\n  #resolve = undefined;\n\n  /**\n   * Callback function to call while user is scrolling, throttled every 50ms.\n   * @type {() => void}\n   */\n  #throttledCallback;\n\n  /**\n   * Callback function invoked after user scroll ends.\n   * @type {() => void}\n   */\n  #endCallback;\n\n  /**\n   * Callback function invoked when scrolling starts, regardless of whether it was triggered by a user event.\n   * @type {(() => void) | undefined}\n   */\n  #onScrollInit;\n\n  /**\n   * Callback function invoked when scrolling ends, regardless of whether it was triggered by a user event.\n   * @type {(() => void) | undefined}\n   */\n  #onScrollEnd;\n\n  /**\n   * Whether the scroll was triggered by a user event.\n   * @type {boolean}\n   */\n  #userEvent = true;\n\n  /**\n   * Whether the next scroll event should be ignored.\n   * @type {boolean}\n   */\n  #ignore = false;\n\n  /**\n   * Whether the element is currently scrolling.\n   * @type {boolean}\n   */\n  #isScrolling = false;\n\n  /**\n   * Creates a Scroller instance.\n   *\n   * @param {HTMLElement} element - The element to apply scrolling to.\n   * @param {Object} options - The options for the scroller.\n   * @param {() => void} options.onScroll - Function to call while scrolling and after scrolling ends.\n   * @param {() => void} [options.onScrollStart] - Function to call when scrolling starts.\n   * @param {() => void} [options.onScrollEnd] - Function to call after scrolling ends.\n   */\n  constructor(element, options) {\n    this.#throttledCallback = throttle(options.onScroll, SCROLL_END_TIMEOUT);\n    this.#endCallback = options.onScroll;\n\n    this.#onScrollInit = options.onScrollStart;\n    this.#onScrollEnd = options.onScrollEnd;\n\n    this.element = element;\n    this.element.addEventListener('scroll', this.#handleScroll);\n  }\n\n  /**\n   * Scrolls to a specific position or element.\n   * @param {number | HTMLElement} input - The position in pixels or an element to scroll to.\n   * @param {Object} [options] - Options for the scroll.\n   * @param {boolean} [options.instant] - Whether to scroll instantly.\n   */\n  async to(input, options) {\n    let value;\n\n    if (input instanceof HTMLElement) {\n      const paddingStart = calculatePaddingStart(this.element, this.axis);\n      value = input[`offset${this.#edge}`] - paddingStart;\n    } else {\n      value = input;\n    }\n\n    const currentPosition = this.element[`scroll${this.#edge}`];\n    const willChange = currentPosition !== value;\n\n    if (willChange) {\n      this.#scroll({ ...options, method: 'scrollTo', value });\n    } else if (this.#isScrolling) {\n      // If the scroll has started but then it's released in the same original position,\n      // the scroll event will not fire, so we need to manually trigger the scroll end.\n      this.#handleScrollEnd(false);\n    }\n  }\n\n  /**\n   * Scrolls by a certain number of pixels.\n   * @param {number} value - The number of pixels to scroll by.\n   * @param {Object} [options] - Options for the scroll.\n   * @param {boolean} [options.instant] - Whether to scroll instantly.\n   */\n  by(value, options) {\n    this.#scroll({ ...options, method: 'scrollBy', value });\n  }\n\n  /**\n   * Scrolls the element.\n   * @param {Object} options - The options for the scroll.\n   * @param {'scrollTo' | 'scrollBy'} options.method - The method to use to scroll.\n   * @param {number} options.value - The value to scroll to.\n   * @param {boolean} [options.instant] - Whether to scroll instantly.\n   */\n  #scroll(options) {\n    const { method, value, instant = prefersReducedMotion() } = options;\n\n    this.#reset();\n    this.#ignore = instant;\n    this.#userEvent = false;\n\n    // Check if we need to scroll at all\n    const currentPosition = this.element[`scroll${this.#edge}`];\n    const targetPosition = method === 'scrollBy' ? currentPosition + value : value;\n    const scrollDistance = Math.abs(targetPosition - currentPosition);\n\n    // If the distance is negligible, don't scroll and resolve immediately\n    if (scrollDistance < 1) {\n      return Promise.resolve();\n    }\n\n    if (!instant) this.#setup();\n\n    this.element[method]({\n      [this.#edge.toLowerCase()]: value,\n      behavior: instant ? 'instant' : 'smooth',\n    });\n  }\n\n  /**\n   * Gets the scrolling axis ('x' or 'y') based on the element's dimensions.\n   * @type {'x' | 'y'}\n   * @readonly\n   */\n  get axis() {\n    return getScrollAxis(this.element);\n  }\n\n  /**\n   * Promise that resolves when scrolling ends.\n   * @type {Promise<void>}\n   * @readonly\n   */\n  get finished() {\n    return this.#promise ?? Promise.resolve();\n  }\n\n  /**\n   * Gets the scroll edge property ('Left' or 'Top') based on the axis.\n   * @returns {'Left' | 'Top'}\n   */\n  get #edge() {\n    return this.axis === 'x' ? 'Left' : 'Top';\n  }\n\n  /**\n   * Sets up the scroll end promise if not already set.\n   */\n  #setup() {\n    if (this.#promise) {\n      return;\n    }\n\n    this.#promise = new Promise((resolve) => (this.#resolve = resolve));\n  }\n\n  #reset = () => {\n    this.#handleScrollEnd.cancel();\n    this.#resolve?.();\n\n    this.#promise = undefined;\n    this.#resolve = undefined;\n    this.#userEvent = true;\n    this.#ignore = false;\n  };\n\n  /**\n   * Event handler for the 'scroll' event.\n   */\n  #handleScroll = () => {\n    if (!this.#isScrolling) {\n      this.#onScrollInit?.();\n      this.#isScrolling = true;\n    }\n\n    if (this.#ignore) {\n      this.#reset();\n      this.#handleScrollEnd(false);\n      return;\n    }\n\n    const userEvent = this.#userEvent;\n\n    this.#setup();\n    if (userEvent) this.#throttledCallback();\n    this.#handleScrollEnd(userEvent);\n  };\n\n  /**\n   * Handler called when scrolling has ended.\n   */\n  #handleScrollEnd = debounce(\n    /**\n     * @param {boolean} userEvent\n     */\n    (userEvent) => {\n      this.#resolve?.();\n      if (userEvent) this.#endCallback();\n      this.#reset();\n\n      if (this.#isScrolling) {\n        this.#onScrollEnd?.();\n        this.#isScrolling = false;\n      }\n    },\n    SCROLL_END_TIMEOUT\n  );\n\n  /**\n   * Sets the scroll snap behavior of the element.\n   * @param {boolean} value - Whether to enable scroll snap.\n   */\n  set snap(value) {\n    // Changing the snap behavior will trigger a scroll event, which we should ignore\n    this.#ignore = true;\n    this.element.style.setProperty('scroll-snap-type', value ? `${this.axis} mandatory` : 'none');\n  }\n\n  /**\n   * Destroys the Scroller instance.\n   */\n  destroy() {\n    this.element.removeEventListener('scroll', this.#handleScroll);\n  }\n}\n\n/**\n * Gets the scroll axis ('x' or 'y') based on the element's dimensions.\n * @param {HTMLElement} el - The element to get the scroll axis of.\n * @returns {'x' | 'y'}\n */\nfunction getScrollAxis(el) {\n  if (el.scrollHeight > el.clientHeight && el.scrollWidth === el.clientWidth) {\n    return 'y';\n  }\n\n  if (el.scrollWidth > el.clientWidth && el.scrollHeight === el.clientHeight) {\n    return 'x';\n  }\n\n  return el.scrollWidth > el.scrollHeight ? 'x' : 'y';\n}\n\n/**\n * Calculates the padding-start around an element to update the scroll offset.\n * @param {HTMLElement} element - The element to calculate the padding-start of.\n * @param {'x' | 'y'} axis - The axis to calculate the padding-start of.\n * @returns {number} The padding-start in pixels.\n */\nfunction calculatePaddingStart(element, axis) {\n  const computedStyle = getComputedStyle(element);\n  const value = axis === 'x' ? computedStyle.paddingInlineStart : computedStyle.paddingBlockStart;\n\n  return parseFloat(value);\n}\n\n/**\n * Scrolls an element into view.\n * @param {Element} element - The element to scroll into view.\n * @param {Object} options - The options for the scroll.\n * @param {ScrollBehavior} [options.behavior='smooth'] - The behavior of the scroll.\n * @param {'start' | 'center' | 'end'} [options.block='start'] - The block alignment of the element.\n * @param {'start' | 'center' | 'end'} [options.inline='start'] - The inline alignment of the element.\n * @param {Element} [options.ancestor] - The ancestor element to scroll into view.\n */\nexport function scrollIntoView(element, { ancestor, behavior = 'smooth', block = 'start', inline = 'start' } = {}) {\n  if (!ancestor) {\n    return element.scrollIntoView({ behavior, block, inline });\n  }\n\n  const elemRect = element.getBoundingClientRect();\n  const ancestorRect = ancestor.getBoundingClientRect();\n\n  /**\n   * Calculates the scroll offset for an element.\n   * @param {'start' | 'center' | 'end'} alignment - The alignment of the element.\n   * @param {number} ancestorStart - The start of the ancestor element.\n   * @param {number} ancestorLength - The length of the ancestor element.\n   * @param {number} elemStart - The start of the element.\n   * @param {number} elemLength - The length of the element.\n   * @param {number} currentScroll - The current scroll position.\n   * @returns {number} The scroll offset.\n   */\n  const calculateScrollOffset = (alignment, ancestorStart, ancestorLength, elemStart, elemLength, currentScroll) => {\n    switch (alignment) {\n      case 'start':\n        return currentScroll + elemStart - ancestorStart;\n      case 'center':\n        return currentScroll + elemStart - ancestorStart - ancestorLength / 2 + elemLength / 2;\n      case 'end':\n        return currentScroll + elemStart - ancestorStart - ancestorLength + elemLength;\n      default:\n        return currentScroll;\n    }\n  };\n\n  const scrollTop =\n    ancestor.scrollHeight > ancestor.clientHeight\n      ? calculateScrollOffset(\n          block,\n          ancestorRect.top,\n          ancestor.clientHeight,\n          elemRect.top,\n          elemRect.height,\n          ancestor.scrollTop\n        )\n      : ancestor.scrollTop;\n\n  const scrollLeft =\n    ancestor.scrollWidth > ancestor.clientWidth\n      ? calculateScrollOffset(\n          inline,\n          ancestorRect.left,\n          ancestor.clientWidth,\n          elemRect.left,\n          elemRect.width,\n          ancestor.scrollLeft\n        )\n      : ancestor.scrollLeft;\n\n  ancestor.scrollTo({ top: scrollTop, left: scrollLeft, behavior });\n}\n\n// Still extends HTMLElement over Component so that refs are still available to parent components (e.g. Slideshow)\nclass ScrollHint extends HTMLElement {\n  /** @type {number | null} */\n  #rafId = null;\n\n  connectedCallback() {\n    this.addEventListener('scroll', this.#handleScroll);\n    this.#resizeObserver.observe(this);\n  }\n\n  disconnectedCallback() {\n    this.removeEventListener('scroll', this.#handleScroll);\n    this.#resizeObserver.disconnect();\n    if (this.#rafId !== null) {\n      cancelAnimationFrame(this.#rafId);\n      this.#rafId = null;\n    }\n  }\n\n  #handleScroll = () => {\n    // Throttle scroll updates with requestAnimationFrame to avoid layout thrashing\n    if (this.#rafId !== null) return;\n\n    this.#rafId = requestAnimationFrame(() => {\n      this.#rafId = null;\n      this.#update();\n    });\n  };\n\n  #update = () => {\n    const { scrollTop, scrollHeight, clientHeight, scrollLeft, scrollWidth, clientWidth } = this;\n    const scrollDirection = scrollWidth > clientWidth ? 'horizontal' : 'vertical';\n    const scrollPercentage =\n      scrollDirection === 'vertical'\n        ? scrollTop / (scrollHeight - clientHeight)\n        : scrollLeft / (scrollWidth - clientWidth);\n\n    this.style.maskImage = Number.isNaN(scrollPercentage)\n      ? ''\n      : `linear-gradient(\n        to ${scrollDirection === 'vertical' ? 'bottom' : 'right'},\n        transparent ${scrollPercentage > 0 ? 1 : 0}%,\n        black ${scrollPercentage < 0.1 ? scrollPercentage * 100 : 10}%,\n        black ${scrollPercentage > 0.9 ? scrollPercentage * 100 : 90}%,\n        transparent 100%\n      )`;\n  };\n\n  #resizeObserver = new ResizeObserver(this.#update);\n}\n\nif (!customElements.get('scroll-hint')) {\n  customElements.define('scroll-hint', ScrollHint);\n}\n"],
  "mappings": "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",
  "names": []
}
