UNPKG

@chayns-components/core

Version:

A set of beautiful React components for developing your own applications with chayns.

298 lines (296 loc) • 11.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _chaynsApi = require("chayns-api"); var _react = require("motion/react"); var _react2 = _interopRequireWildcard(require("react")); var _element = require("../../hooks/element"); var _calculate = require("../../utils/calculate"); var _sliderButton = require("../../utils/sliderButton"); var _Icon = _interopRequireDefault(require("../icon/Icon")); var _Popup = _interopRequireDefault(require("../popup/Popup")); var _SliderButton = require("./SliderButton.styles"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } const SliderButton = ({ selectedButtonId, isDisabled, items, onChange }) => { const [dragRange, setDragRange] = (0, _react2.useState)({ left: 0, right: 0 }); const [shownItemsCount, setShownItemsCount] = (0, _react2.useState)(items.length); const [sliderSize, setSliderSize] = (0, _react2.useState)({ width: 0 }); const [currentId, setCurrentId] = (0, _react2.useState)(''); const [currentPopupId, setCurrentPopupId] = (0, _react2.useState)(''); const [currentIndex, setCurrentIndex] = (0, _react2.useState)(0); const sliderButtonRef = (0, _react2.useRef)(null); const sliderButtonWrapperRef = (0, _react2.useRef)(null); const popupRef = (0, _react2.useRef)(null); const [scope, animate] = (0, _react.useAnimate)(); const initialItemWidth = (0, _react2.useMemo)(() => (0, _calculate.calculateBiggestWidth)(items), [items]); const elementSize = (0, _element.useElementSize)(sliderButtonRef); (0, _react2.useEffect)(() => { if (elementSize) setSliderSize(elementSize); }, [elementSize]); const setPopupId = (0, _react2.useCallback)(selectedId => { const ids = items.slice(shownItemsCount - 1).map(({ id }) => id); const newId = ids.find(id => id === selectedId); if (newId) { setCurrentId('more'); setCurrentPopupId(newId); return; } setCurrentId(selectedId); }, [items, shownItemsCount]); const isSliderBigger = (0, _react2.useMemo)(() => sliderSize && Math.floor(sliderSize.width / initialItemWidth) < items.length - 1, [initialItemWidth, items.length, sliderSize]); const maxShownItemsCount = (0, _react2.useMemo)(() => { let totalWidth = 0; let count = 0; while (count < items.length) { const visibleItems = items.slice(0, count + 1); const currentMaxWidth = (0, _calculate.calculateBiggestWidth)(visibleItems) + 8; if (totalWidth + currentMaxWidth > sliderSize.width) break; totalWidth += currentMaxWidth; count++; } return count; }, [items, sliderSize.width]); const itemWidth = (0, _react2.useMemo)(() => { const sliderWidth = (sliderSize === null || sliderSize === void 0 ? void 0 : sliderSize.width) || 0; const itemCount = items.length || 1; setShownItemsCount(isSliderBigger ? maxShownItemsCount : itemCount); return sliderWidth / (isSliderBigger ? maxShownItemsCount : itemCount); }, [isSliderBigger, items.length, maxShownItemsCount, sliderSize === null || sliderSize === void 0 ? void 0 : sliderSize.width]); (0, _react2.useEffect)(() => { if (sliderSize) { const sliderWidth = itemWidth * (items.length - 1); const count = Math.floor(sliderSize.width / itemWidth); setDragRange({ left: 0, right: isSliderBigger ? itemWidth * count : sliderWidth }); } }, [isSliderBigger, itemWidth, items.length, sliderSize]); const animation = (0, _react2.useCallback)(async x => { await animate(scope.current, { x }, { type: 'tween', duration: 0.2 }); }, [animate, scope]); const setItemPosition = (0, _react2.useCallback)(index => { setCurrentIndex(index); void animation(itemWidth * index); }, [animation, itemWidth]); (0, _react2.useEffect)(() => { if (typeof selectedButtonId === 'string') { let index = items.findIndex(({ id }) => id === selectedButtonId); setCurrentId(selectedButtonId); setPopupId(selectedButtonId); if (items.length > shownItemsCount && index > shownItemsCount - 1) { index = shownItemsCount - 1; } if (index >= 0) { setItemPosition(index); } } }, [animation, dragRange.right, isSliderBigger, itemWidth, items, selectedButtonId, setItemPosition, setPopupId, shownItemsCount]); const handleClick = (0, _react2.useCallback)((id, index) => { if (isDisabled) { return; } setPopupId(id); if (typeof onChange === 'function' && id !== 'more') { onChange(id); } if (popupRef.current) { if (id === 'more') { popupRef.current.show(); } else { popupRef.current.hide(); } } setItemPosition(index); }, [isDisabled, onChange, setItemPosition, setPopupId]); const buttons = (0, _react2.useMemo)(() => { if (items.length > shownItemsCount) { const newItems = items.slice(0, shownItemsCount - 1); const otherItems = items.slice(shownItemsCount - 1); const elements = newItems.map(({ id, text }, index) => /*#__PURE__*/_react2.default.createElement(_SliderButton.StyledSliderButtonItem, { $width: itemWidth, key: `slider-button-${id}`, onClick: () => handleClick(id, index) }, text)); const popupContent = otherItems.map(({ id, text }) => /*#__PURE__*/_react2.default.createElement(_SliderButton.StyledSliderButtonPopupContentItem, { key: `slider-button-${id}`, onClick: () => handleClick(id, newItems.length), $isSelected: id === currentPopupId }, text)); const id = 'more'; elements.push(/*#__PURE__*/_react2.default.createElement(_SliderButton.StyledSliderButtonItem, { $width: itemWidth, key: `slider-button-${id}` }, /*#__PURE__*/_react2.default.createElement(_Popup.default, { ref: popupRef, content: /*#__PURE__*/_react2.default.createElement(_SliderButton.StyledSliderButtonPopupContent, null, popupContent) }, /*#__PURE__*/_react2.default.createElement(_Icon.default, { icons: ['fa fa-ellipsis'], color: "white" })))); return elements; } return items.map(({ id, text }) => /*#__PURE__*/_react2.default.createElement(_SliderButton.StyledSliderButtonItem, { $width: itemWidth, key: `slider-button-${id}` }, text)); }, [currentPopupId, handleClick, itemWidth, items, shownItemsCount]); const pseudoButtons = (0, _react2.useMemo)(() => { if (items.length > shownItemsCount) { const newItems = items.slice(0, shownItemsCount - 1); const elements = newItems.map(({ id, text }, index) => /*#__PURE__*/_react2.default.createElement(_SliderButton.StyledSliderButtonItem, { $width: itemWidth, key: `pseudo-slider-button-${id}`, onClick: () => handleClick(id, index) }, text)); const id = 'more'; elements.push(/*#__PURE__*/_react2.default.createElement(_SliderButton.StyledSliderButtonItem, { $width: itemWidth, key: `pseudo-slider-button-${id}`, onClick: () => handleClick(id, newItems.length) }, /*#__PURE__*/_react2.default.createElement(_Icon.default, { icons: ['fa fa-ellipsis'] }))); return elements; } return items.map(({ id, text }, index) => /*#__PURE__*/_react2.default.createElement(_SliderButton.StyledSliderButtonItem, { $width: itemWidth, key: `pseudo-slider-button-${id}`, onClick: () => handleClick(id, index) }, text)); }, [handleClick, itemWidth, items, shownItemsCount]); /** * Creates an array with the snap points relative to the width of the items */ const snapPoints = (0, _react2.useMemo)(() => { const points = [0]; for (let i = 1; i < items.length; i++) { points.push(itemWidth * i); } return points; }, [itemWidth, items.length]); const handleDragStart = (0, _react2.useCallback)(() => { void (0, _chaynsApi.setRefreshScrollEnabled)(false); }, []); const handleDragEnd = (0, _react2.useCallback)(() => { void (0, _chaynsApi.setRefreshScrollEnabled)(true); const position = (0, _sliderButton.getThumbPosition)({ scope, itemWidth }); if (!position) { return; } const { middle, left } = position; let scrollLeft = 0; if (sliderButtonWrapperRef.current) { scrollLeft = sliderButtonWrapperRef.current.scrollLeft; sliderButtonWrapperRef.current.scrollLeft = (0, _sliderButton.getNearestPoint)({ snapPoints, position: middle, scrollLeft: scrollLeft - left }).nearestPoint; } const { nearestIndex } = (0, _sliderButton.getNearestPoint)({ snapPoints, position: middle, scrollLeft }); const { nearestPoint } = (0, _sliderButton.getNearestPoint)({ snapPoints, position: middle, scrollLeft: 0 }); if (nearestPoint >= 0 && nearestIndex >= 0) { void animation(nearestPoint); let id; if (nearestIndex === shownItemsCount - 1) { id = 'more'; } else { var _items$nearestIndex; id = (_items$nearestIndex = items[nearestIndex]) === null || _items$nearestIndex === void 0 ? void 0 : _items$nearestIndex.id; } if (popupRef.current) { if (id === 'more') { popupRef.current.show(); } else { popupRef.current.hide(); } } if (typeof onChange === 'function' && id && id !== 'more') { onChange(id); } } }, [animation, itemWidth, items, onChange, scope, shownItemsCount, snapPoints]); return (0, _react2.useMemo)(() => /*#__PURE__*/_react2.default.createElement(_SliderButton.StyledSliderButton, { $isDisabled: isDisabled, ref: sliderButtonRef }, /*#__PURE__*/_react2.default.createElement(_SliderButton.StyledSliderButtonButtonsWrapper, { $isInvisible: true }, pseudoButtons), /*#__PURE__*/_react2.default.createElement(_SliderButton.StyledMotionSliderButtonThumb, { ref: scope, drag: isDisabled ? false : 'x', dragElastic: 0, dragConstraints: isSliderBigger ? { ...dragRange, right: dragRange.right - itemWidth } : { ...dragRange }, $width: itemWidth, onDragEnd: handleDragEnd, onDragStart: handleDragStart, onClick: () => handleClick(currentId, currentIndex) }), /*#__PURE__*/_react2.default.createElement(_SliderButton.StyledSliderButtonWrapper, { $isDisabled: isDisabled, $width: !isSliderBigger ? dragRange.right + itemWidth : dragRange.right, ref: sliderButtonWrapperRef }, /*#__PURE__*/_react2.default.createElement(_react.AnimatePresence, null, /*#__PURE__*/_react2.default.createElement(_SliderButton.StyledSliderButtonButtonsWrapper, null, buttons)))), [buttons, currentId, currentIndex, dragRange, handleClick, handleDragEnd, handleDragStart, isDisabled, isSliderBigger, itemWidth, pseudoButtons, scope]); }; SliderButton.displayName = 'SliderButton'; var _default = exports.default = SliderButton; //# sourceMappingURL=SliderButton.js.map