{"version":3,"sources":["../src/slider/slider.tsx","../src/slider/button.tsx","../src/slider/utils/buttons-states.ts","../src/slider/utils/get-previous-offset.ts","../src/slider/utils/smooth-scroll.ts","../src/slider/utils/get-next-offset.ts"],"sourcesContent":["import {\n  Children,\n  FC,\n  ReactNode,\n  useCallback,\n  useEffect,\n  useRef,\n  useState,\n} from \"react\";\nimport SliderButton from \"./button\";\nimport { TOverflowSlider, TButtonsState } from \"./slider.types\";\nimport {\n  updateButtonsDisabled,\n  updateButtonsVisibility,\n} from \"./utils/buttons-states\";\nimport { getPreviousOffset } from \"./utils/get-previous-offset\";\nimport { smoothScroll } from \"./utils/smooth-scroll\";\nimport { getNextOffset } from \"./utils/get-next-offset\";\nimport \"./slider.style.scss\";\n\nconst OverflowSlider: FC<TOverflowSlider> = ({\n  children,\n  prevButton,\n  nextButton,\n  gap = 0,\n  duration = 300,\n}) => {\n  const scrollerRef = useRef<HTMLDivElement | null>(null);\n  const itemsRef = useRef<(HTMLDivElement | null)[]>([]);\n  const scrollWidth = useRef(0);\n\n  const [buttonsState, setButtonsState] = useState<TButtonsState>({\n    prevButtonVisible: false,\n    nextButtonVisible: false,\n    prevButtonDisabled: false,\n    nextButtonDisabled: false,\n  });\n\n  const checkShowButtons = useCallback(() => {\n    if (scrollerRef.current) {\n      updateButtonsVisibility(scrollerRef.current, setButtonsState);\n    }\n  }, [scrollerRef]);\n\n  const setDisabledButtons = useCallback(() => {\n    updateButtonsDisabled(setButtonsState, true);\n    setTimeout(() => {\n      updateButtonsDisabled(setButtonsState, false);\n    }, duration + 50);\n  }, [duration]);\n\n  const handleScrollPrevious = useCallback(() => {\n    if (scrollerRef.current && itemsRef?.current?.length) {\n      const previousOffset = getPreviousOffset(\n        scrollerRef.current,\n        itemsRef.current,\n      );\n      smoothScroll(scrollerRef.current, previousOffset, duration);\n      setDisabledButtons();\n    }\n  }, [scrollerRef, itemsRef, setDisabledButtons, duration]);\n\n  const handleScrollNext = useCallback(() => {\n    if (scrollerRef.current && itemsRef?.current?.length) {\n      const nextOffset = getNextOffset(scrollerRef.current, itemsRef.current);\n      smoothScroll(scrollerRef.current, nextOffset, duration);\n      setDisabledButtons();\n    }\n  }, [scrollerRef, itemsRef, setDisabledButtons, duration]);\n\n  useEffect(() => {\n    const handleResize = checkShowButtons;\n    window.addEventListener(\"resize\", handleResize);\n    checkShowButtons();\n    return () => window.removeEventListener(\"resize\", handleResize);\n  }, [checkShowButtons]);\n\n  useEffect(() => {\n    if (\n      scrollerRef.current &&\n      scrollerRef.current.scrollWidth !== scrollWidth.current\n    ) {\n      checkShowButtons();\n      scrollWidth.current = scrollerRef.current.scrollWidth;\n    }\n  }, [children, checkShowButtons]);\n\n  return (\n    <div className=\"react-overflow-slider-container\">\n      <div className=\"react-overflow-slider\">\n        <div className=\"react-overflow-slider__btn-container\">\n          <button\n            type=\"button\"\n            role=\"button\"\n            aria-label=\"Scroll to previous\"\n            onClick={handleScrollPrevious}\n            className={`react-overflow-slider__btn react-overflow-slider__btn--prev \n              ${buttonsState.prevButtonDisabled ? \"react-overflow-slider__btn--disabled\" : \"\"} \n              ${buttonsState.prevButtonVisible ? \"react-overflow-slider__btn--visible\" : \"\"}`}\n            style={{ transition: `${duration}ms` }}\n          >\n            {prevButton || <SliderButton left />}\n          </button>\n        </div>\n        <div\n          ref={scrollerRef}\n          className=\"react-overflow-slider__scroller\"\n          onScroll={checkShowButtons}\n        >\n          <div className=\"react-overflow-slider__body\">\n            {Children.map(children, (child: ReactNode, i) => (\n              <div\n                ref={(ref) => (itemsRef.current[i] = ref)}\n                className=\"react-overflow-slider__item\"\n                style={{\n                  ...(gap && i < children.length - 1 && { paddingRight: gap }),\n                }}\n              >\n                {child}\n              </div>\n            ))}\n          </div>\n        </div>\n        <div className=\"react-overflow-slider__btn-container\">\n          <button\n            type=\"button\"\n            role=\"button\"\n            aria-label=\"Scroll to next\"\n            onClick={handleScrollNext}\n            className={`react-overflow-slider__btn react-overflow-slider__btn--next  \n              ${buttonsState.nextButtonDisabled ? \"react-overflow-slider__btn--disabled\" : \"\"} \n              ${buttonsState.nextButtonVisible ? \"react-overflow-slider__btn--visible\" : \"\"}`}\n            style={{ transition: `${duration}ms` }}\n          >\n            {nextButton || <SliderButton />}\n          </button>\n        </div>\n      </div>\n    </div>\n  );\n};\n\nexport default OverflowSlider;\n","const SliderButton = ({ left }: { left?: boolean }) => {\n  return (\n    <div\n      className={`react-overflow-slider-btn ${left ? \"react-overflow-slider-btn--left\" : \"\"} `}\n    >\n      <svg\n        xmlns=\"http://www.w3.org/2000/svg\"\n        viewBox=\"0 0 24 24\"\n        width=\"20\"\n        height=\"20\"\n        fill=\"none\"\n        stroke=\"currentColor\"\n        strokeWidth=\"2\"\n        strokeLinecap=\"round\"\n        strokeLinejoin=\"round\"\n      >\n        <polyline points=\"8 4 16 12 8 20\" />\n      </svg>\n    </div>\n  );\n};\n\nexport default SliderButton;\n","import { Dispatch, SetStateAction } from \"react\";\nimport { TButtonsState } from \"@/slider/slider.types\";\n\nexport function updateButtonsVisibility(\n  scroller: HTMLDivElement,\n  setButtonsState: Dispatch<SetStateAction<TButtonsState>>,\n) {\n  const { offsetWidth, scrollLeft, scrollWidth } = scroller;\n  setButtonsState((state) => ({\n    ...state,\n    prevButtonVisible: scrollLeft > 0,\n    nextButtonVisible: scrollLeft + offsetWidth < scrollWidth,\n  }));\n}\n\nexport function updateButtonsDisabled(\n  setButtonsState: Dispatch<SetStateAction<TButtonsState>>,\n  show: boolean,\n) {\n  setButtonsState((state) => ({\n    ...state,\n    prevButtonDisabled: show,\n    nextButtonDisabled: show,\n  }));\n}\n","export function getPreviousOffset(\n  scroller: HTMLDivElement,\n  items: (HTMLDivElement | null)[],\n) {\n  const findFirstVisibleItemIndex = (scrollLeft: number, widths: number[]) => {\n    let first = 0,\n      i = 0;\n    while (first < scrollLeft) {\n      first += widths[i];\n      i++;\n    }\n    return i;\n  };\n\n  const findPreviousItemIndex = (\n    visibleScroll: number,\n    firstVisible: number,\n    widths: number[],\n  ) => {\n    let i = firstVisible,\n      possible = 0;\n    if (widths[i - 1] >= visibleScroll) return i - 1;\n    do {\n      i--;\n      possible += widths[i];\n    } while (possible < visibleScroll && i > -1);\n    return i + 1;\n  };\n\n  const scrollerVisibleWidth = scroller.offsetWidth;\n  const scrollerScrollLeft = scroller.scrollLeft;\n  const itemsWidths = items.map((item) => (item ? item.offsetWidth : 0));\n  const firstVisible = findFirstVisibleItemIndex(\n    scrollerScrollLeft,\n    itemsWidths,\n  );\n  const prevItemIndex = findPreviousItemIndex(\n    scrollerVisibleWidth,\n    firstVisible,\n    itemsWidths,\n  );\n  const itemsOffsetLeft = items.map((item) => (item ? item.offsetLeft : 0));\n\n  return itemsOffsetLeft[prevItemIndex];\n}\n","const easeOutCubic = (t: number) => 1 - Math.pow(1 - t, 3);\n\nexport const smoothScroll = (\n  scroller: HTMLDivElement,\n  end: number,\n  duration: number,\n) => {\n  const start = scroller.scrollLeft;\n  const startTime = performance.now();\n\n  const step = (currentTime: number) => {\n    const elapsed = (currentTime - startTime) / duration;\n    const progress = Math.min(easeOutCubic(elapsed), 1);\n    scroller.scrollLeft = start + (end - start) * progress;\n    if (progress < 1) requestAnimationFrame(step);\n  };\n\n  requestAnimationFrame(step);\n};\n","export function getNextOffset(\n  scroller: HTMLDivElement,\n  items: (HTMLDivElement | null)[],\n) {\n  const findNextItemIndex = (left: number, right: number, widths: number[]) => {\n    let availableWidth = 0;\n    let visibleWidth = 0;\n    let i = 0;\n\n    do {\n      availableWidth += widths[i];\n      i++;\n    } while (right >= availableWidth && i < widths.length);\n\n    i = i - 1;\n    for (let j = 0; j < i; j++) {\n      visibleWidth += widths[j];\n    }\n\n    return visibleWidth <= left ? i + 1 : i;\n    // ⚠️ Potential Issue with Font-Based Width Calculations:\n    // When elements have widths influenced by fonts, fractional values can cause rounding errors.\n    // Example:\n    //   79.68 + 81.73 rounds to 80 + 82 = 162,\n    //   but scrollLeft might return 161.41, which rounds to 161.\n    // This mismatch can result in infinite loops or prevent scrolling to the next element.\n    //\n    // 💡 Solutions:\n    // 1. Use universal fonts (e.g., system-native fonts, sans-serif) for consistent rendering across OS.\n    //    Note: Fonts like Arial may render inconsistently on macOS.\n    // 2. Apply a tolerance range in the condition:\n    //    Change the condition to (visibleWidth - n <= left), where **n** is the pixel tolerance.\n    //    Increase **n** as the scroll moves further left to account for larger cumulative rounding errors.\n  };\n\n  const scrollerVisibleWidth = scroller.offsetWidth;\n  const scrollerScrollLeft = scroller.scrollLeft;\n  const scrollerScrollRight = scrollerScrollLeft + scrollerVisibleWidth;\n  const itemsWidths = items.map((item) => (item ? item.offsetWidth : 0));\n  const itemsOffsetLeft = items.map((item) => (item ? item.offsetLeft : 0));\n  const nextItemIndex = findNextItemIndex(\n    scrollerScrollLeft,\n    scrollerScrollRight,\n    itemsWidths,\n  );\n  const scrollerWidth = scroller.scrollWidth;\n  const possibleScroll = scrollerWidth - scrollerVisibleWidth + 1;\n  const nextItem =\n    nextItemIndex !== items.length ? itemsOffsetLeft[nextItemIndex] : null;\n\n  return nextItem !== null && possibleScroll >= nextItem\n    ? nextItem\n    : possibleScroll;\n}\n"],"mappings":"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","names":["firstVisible","jsx"]}