@chayns-components/core
Version:
A set of beautiful React components for developing your own applications with chayns.
298 lines (296 loc) • 11.9 kB
JavaScript
;
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