UNPKG

@kiwicom/orbit-components

Version:

Orbit-components is a React component library which provides developers with the easiest possible way of building Kiwi.com's products.

182 lines (181 loc) 6.29 kB
"use strict"; "use client"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default; exports.__esModule = true; exports.default = void 0; var React = _interopRequireWildcard(require("react")); var _clsx = _interopRequireDefault(require("clsx")); var _Stack = _interopRequireDefault(require("../Stack")); var _mergeRefs = _interopRequireDefault(require("../utils/mergeRefs")); var _useTheme = _interopRequireDefault(require("../hooks/useTheme")); var _useScroll = _interopRequireDefault(require("./useScroll")); var _ChevronBackward = _interopRequireDefault(require("../icons/ChevronBackward")); var _ChevronForward = _interopRequireDefault(require("../icons/ChevronForward")); const getSnap = scrollSnap => { if (scrollSnap === "mandatory") return "x mandatory"; if (scrollSnap === "proximity") return "x proximity"; return scrollSnap; }; const ArrowButton = ({ children, className, isHidden, onClick, ariaLabel }) => { return /*#__PURE__*/React.createElement("button", { className: (0, _clsx.default)("z-default absolute flex h-full items-center", isHidden && "invisible", className), onClick: onClick, type: "button", "aria-label": ariaLabel }, children); }; const ElevationHaze = ({ className, style }) => { return /*#__PURE__*/React.createElement("div", { className: (0, _clsx.default)("z-default absolute top-0 h-full", className), style: style }); }; const HorizontalScroll = ({ children, spacing = "300", arrows, arrowColor, arrowLeftAriaLabel, arrowRightAriaLabel, scrollSnap = "none", onOverflow, elevationColor = "paletteCloudDark", overflowElevation, scrollPadding, dataTest, id, minHeight, ref }) => { const scrollWrapperRef = React.useRef(null); const [isOverflowing, setOverflowing] = React.useState(false); const [reachedStart, setReachedStart] = React.useState(true); const [reachedEnd, setReachedEnd] = React.useState(false); const containerRef = React.useRef(null); const { isDragging } = (0, _useScroll.default)(scrollWrapperRef); const theme = (0, _useTheme.default)(); const scrollEl = scrollWrapperRef.current; const handleOverflow = React.useCallback(() => { if (scrollWrapperRef.current?.scrollWidth && containerRef.current?.offsetWidth) { const { scrollWidth: containerScrollWidth } = scrollWrapperRef.current; const { offsetWidth } = containerRef.current; if (containerScrollWidth > offsetWidth) { setOverflowing(true); if (onOverflow) onOverflow(); } else { setOverflowing(false); } } }, [onOverflow]); const handleClick = direction => { if (scrollEl) { const { scrollLeft, offsetWidth } = scrollEl; const scrollAmount = scrollLeft + (direction === "left" ? -offsetWidth / 2 : offsetWidth / 2); scrollEl.scrollTo({ left: scrollAmount, behavior: "smooth" }); } }; const handleScroll = React.useCallback(() => { if (scrollEl) { const scrollWidth = scrollEl.scrollWidth - scrollEl.clientWidth; const { scrollLeft } = scrollEl; if (scrollLeft === 0) { setReachedStart(true); } else { setReachedStart(false); } if (scrollLeft >= scrollWidth) { setReachedEnd(true); } else { setReachedEnd(false); } } }, [scrollEl]); const handleResize = React.useCallback(() => { handleOverflow(); handleScroll(); }, [handleOverflow, handleScroll]); React.useEffect(() => { handleOverflow(); window.addEventListener("resize", handleResize); return () => { window.removeEventListener("resize", handleResize); }; }, [handleOverflow, handleResize, scrollWrapperRef.current?.scrollWidth]); return /*#__PURE__*/React.createElement("div", { className: (0, _clsx.default)("orbit-horizontal-scroll relative inline-flex w-full items-center overflow-hidden", isOverflowing && (isDragging ? "cursor-grabbing" : "cursor-grab")), "data-test": dataTest, "data-overflowing": isOverflowing || undefined, id: id, ref: (0, _mergeRefs.default)([ref, containerRef]), style: { minHeight } }, overflowElevation && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ElevationHaze, { className: (0, _clsx.default)("left-0", (!isOverflowing || reachedStart) && "invisible"), style: { boxShadow: `5px 0px 20px 20px ${theme.orbit[elevationColor]}` } }), /*#__PURE__*/React.createElement(ElevationHaze, { className: (0, _clsx.default)("right-0", (!isOverflowing || reachedEnd) && "invisible"), style: { boxShadow: `-5px 0px 20px 20px ${theme.orbit[elevationColor]}` } })), arrows && /*#__PURE__*/React.createElement(ArrowButton, { className: "left-100", isHidden: reachedStart || !isOverflowing, onClick: () => handleClick("left"), ariaLabel: arrowLeftAriaLabel }, /*#__PURE__*/React.createElement(_ChevronBackward.default, { ariaHidden: true, customColor: arrowColor })), /*#__PURE__*/React.createElement("div", { className: "scrollbar-none size-full overflow-x-auto overflow-y-hidden", ref: scrollWrapperRef, onScroll: handleScroll, style: { scrollPadding, scrollSnapType: isDragging ? "none" : getSnap(scrollSnap) } }, /*#__PURE__*/React.createElement("div", { className: (0, _clsx.default)("relative inline-flex size-full", isDragging && "pointer-events-none") // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex , tabIndex: isOverflowing ? 0 : undefined }, /*#__PURE__*/React.createElement(_Stack.default, { inline: true, spacing: spacing }, children))), arrows && /*#__PURE__*/React.createElement(ArrowButton, { className: "right-100", isHidden: reachedEnd || !isOverflowing, onClick: () => handleClick("right"), ariaLabel: arrowRightAriaLabel }, /*#__PURE__*/React.createElement(_ChevronForward.default, { ariaHidden: true, customColor: arrowColor }))); }; var _default = exports.default = HorizontalScroll;