react-card-carousel-materialui
Version:
A full-screen card carousel designed in Material UI, drawing inspiration from the Tesla website.
696 lines (682 loc) • 21 kB
JavaScript
import React__default, { useRef, Fragment, useState, useEffect, createElement } from 'react';
import Box from '@mui/material/Box';
import Dialog from '@mui/material/Dialog';
import Stack from '@mui/material/Stack';
import PropTypes from 'prop-types';
import ChevronLeft from '@mui/icons-material/ChevronLeft';
import ChevronRight from '@mui/icons-material/ChevronRight';
import IconButton from '@mui/material/IconButton';
import Close from '@mui/icons-material/Close';
import Card from '@mui/material/Card';
import CardContent from '@mui/material/CardContent';
import Grid from '@mui/material/Grid';
import Typography from '@mui/material/Typography';
function _extends() {
_extends = Object.assign ? Object.assign.bind() : function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
/**
* The base breakpoints for the Soft UI Dashboard PRO React.
* You can add new breakpoints using this file.
* You can customized the breakpoints for the entire Soft UI Dashboard PRO React using thie file.
*/
var breakpoints = {
values: {
xs: 0,
sm: 576,
md: 768,
lg: 992,
xl: 1200,
xxl: 1400
}
};
var SliderActions = function SliderActions(_ref) {
var isNextItemAvailable = _ref.isNextItemAvailable,
isPreviousItemAvailable = _ref.isPreviousItemAvailable,
moveToNext = _ref.moveToNext,
moveToPrevious = _ref.moveToPrevious;
//create a ref for next and previous button
var nextButtonRef = useRef(null);
var previousButtonRef = useRef(null);
return /*#__PURE__*/React__default.createElement(Fragment, null, isNextItemAvailable() && /*#__PURE__*/React__default.createElement(Box, {
style: {
position: 'absolute',
top: '50%',
right: 10,
transform: 'translateY(-50%)',
backgroundColor: 'transparent',
height: '100%',
width: window.innerWidth > breakpoints.values.md ? '10%' : '0px',
zIndex: 10
},
onMouseEnter: function onMouseEnter(event) {
if (nextButtonRef && window.innerWidth > breakpoints.values.md) {
nextButtonRef.current.style.opacity = 1;
}
},
onMouseLeave: function onMouseLeave(event) {
if (nextButtonRef && window.innerWidth > breakpoints.values.md) {
nextButtonRef.current.style.opacity = window.innerWidth < breakpoints.values.md ? 0.5 : 0.1;
}
}
}, /*#__PURE__*/React__default.createElement(Box
// Add the ref to the button
, _extends({
ref: nextButtonRef,
style: _extends({
position: 'absolute',
top: '50%',
right: 10,
transform: 'translateY(-50%)',
zIndex: 10,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '25%',
width: '50px',
cursor: 'pointer',
backgroundColor: 'rgba(0, 0, 0, 0.6)'
}, window.innerWidth < breakpoints.values.md ? {
opacity: 0.5
} : {
opacity: 0.1
}, {
transition: 'opacity 0.5s',
borderRadius: '15px'
})
}, window.innerWidth > breakpoints.values.md && {
onMouseEnter: function onMouseEnter(event) {
event.target.style.opacity = 1;
},
onMouseLeave: function onMouseLeave(event) {
event.target.style.opacity = 0.1;
}
}, {
onClick: moveToNext
}), /*#__PURE__*/React__default.createElement(IconButton, {
color: "white",
style: {
color: 'white',
zIndex: 99
}
}, /*#__PURE__*/React__default.createElement(ChevronRight, {
fontSize: "large"
})))), isPreviousItemAvailable() && /*#__PURE__*/React__default.createElement(Box, {
style: {
position: 'absolute',
top: '50%',
left: 10,
transform: 'translateY(-50%)',
backgroundColor: 'transparent',
height: '100%',
width: window.innerWidth > breakpoints.values.md ? '10%' : '0px',
zIndex: 10
},
onMouseEnter: function onMouseEnter(event) {
if (previousButtonRef && window.innerWidth > breakpoints.values.md) {
previousButtonRef.current.style.opacity = 1;
}
},
onMouseLeave: function onMouseLeave(event) {
if (previousButtonRef && window.innerWidth > breakpoints.values.md) {
previousButtonRef.current.style.opacity = window.innerWidth < breakpoints.values.md ? 0.5 : 0.1;
}
}
}, /*#__PURE__*/React__default.createElement(Box
// Add the ref to the button
, _extends({
ref: previousButtonRef,
style: _extends({
position: 'absolute',
top: '50%',
left: 10,
transform: 'translateY(-50%)',
zIndex: 10,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '25%',
width: '50px',
cursor: 'pointer',
backgroundColor: 'rgba(0, 0, 0, 0.6)'
}, window.innerWidth < breakpoints.values.md ? {
opacity: 0.5
} : {
opacity: 0.1
}, {
transition: 'opacity 0.5s',
borderRadius: '15px'
})
}, window.innerWidth > breakpoints.values.md && {
onMouseEnter: function onMouseEnter(event) {
event.target.style.opacity = 1;
},
onMouseLeave: function onMouseLeave(event) {
event.target.style.opacity = 0.1;
}
}, {
onClick: moveToPrevious
}), /*#__PURE__*/React__default.createElement(IconButton, {
color: "white"
}, /*#__PURE__*/React__default.createElement(ChevronLeft, {
fontSize: "large"
})))));
};
SliderActions.propTypes = {
isNextItemAvailable: PropTypes.func.isRequired,
isPreviousItemAvailable: PropTypes.func.isRequired,
moveToNext: PropTypes.func.isRequired,
moveToPrevious: PropTypes.func.isRequired
};
SliderActions.defaultProps = {
isNextItemAvailable: function isNextItemAvailable() {},
isPreviousItemAvailable: function isPreviousItemAvailable() {},
moveToNext: function moveToNext() {},
moveToPrevious: function moveToPrevious() {}
};
var SliderIndicator = function SliderIndicator(_ref) {
var sliderItems = _ref.sliderItems,
currentItem = _ref.currentItem,
moveToASpecificItem = _ref.moveToASpecificItem;
return /*#__PURE__*/React__default.createElement(Box, {
style: {
textAlign: 'center',
position: 'absolute',
bottom: window.innerWidth < breakpoints.values.md ? '4%' : window.innerWidth < breakpoints.values.lg ? '6%' : '10%',
left: '50%',
transform: 'translateX(-50%)'
}
}, /*#__PURE__*/React__default.createElement(Stack, {
direction: "row",
spacing: 1
}, sliderItems.map(function (item, index) {
return /*#__PURE__*/React__default.createElement(Box, {
key: index,
style: {
width: '10px',
height: '10px',
borderRadius: '50%',
backgroundColor: currentItem === index ? 'white' : 'darkgray',
cursor: 'pointer'
},
onClick: function onClick() {
return moveToASpecificItem(item.id);
}
});
})));
};
SliderIndicator.propTypes = {
sliderItems: PropTypes.array,
currentItem: PropTypes.number,
moveToASpecificItem: PropTypes.func.isRequired
};
SliderIndicator.defaultProps = {
sliderItems: [],
currentItem: 0,
moveToASpecificItem: function moveToASpecificItem() {}
};
// import "@fontsource/open-sans";
var SliderItem = function SliderItem(_ref) {
var id = _ref.id,
index = _ref.index,
isHidden = _ref.isHidden,
video = _ref.video,
image = _ref.image,
title = _ref.title,
description = _ref.description,
actions = _ref.actions,
onlyItem = _ref.onlyItem,
calculateMinWidth = _ref.calculateMinWidth,
onClose = _ref.onClose,
moveToASpecificItem = _ref.moveToASpecificItem;
return /*#__PURE__*/React__default.createElement("div", {
key: id,
id: id
}, isHidden ? /*#__PURE__*/React__default.createElement("div", {
style: {
width: calculateMinWidth(),
minWidth: calculateMinWidth(),
height: '550px',
minHeight: '550px',
marginRight: '30px',
marginLeft: '30px'
}
}) : /*#__PURE__*/React__default.createElement(Card, {
key: index,
style: _extends({
width: calculateMinWidth(),
minWidth: calculateMinWidth(),
height: '550px',
minHeight: '550px',
marginRight: '30px',
marginLeft: '30px'
}, index === 1 || onlyItem ? {
transform: 'scale(1.04)',
transition: 'transform 1s 1s'
} : {
boxShadow: '0 0 10px 0 rgba(0, 0, 0, 0.1)',
transition: 'box-shadow 0.5s',
backgroundColor: 'white'
}, {
padding: 0,
marginTop: 0,
position: 'relative',
borderRadius: '15px'
}),
onClick: function onClick() {
return moveToASpecificItem(id);
}
}, index !== 1 && !onlyItem && /*#__PURE__*/React__default.createElement(Box, {
style: {
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
backgroundColor: 'rgba(0, 0, 0, 0.5)',
backdropFilter: 'blur(1px)',
zIndex: 9,
cursor: 'pointer'
}
}), /*#__PURE__*/React__default.createElement(CardContent, {
style: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '100%',
width: '100%',
marginTop: 0,
padding: 0,
overflow: 'auto'
}
}, /*#__PURE__*/React__default.createElement(Box, {
style: {
position: 'absolute',
top: 0,
right: 0,
margin: '10px',
zIndex: 8
}
}, /*#__PURE__*/React__default.createElement(IconButton, {
onClick: onClose,
color: "info"
}, /*#__PURE__*/React__default.createElement(Close, null))), /*#__PURE__*/React__default.createElement(Grid, {
container: true,
spacing: 2,
style: {
height: '100%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
paddingTop: 0,
marginTop: 0
},
direction: "row"
}, (image || video) && /*#__PURE__*/React__default.createElement(Grid, {
item: true,
xs: window.innerWidth < breakpoints.values.md ? 12 : 7,
style: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
paddingTop: 0,
marginTop: 0,
height: window.innerWidth < breakpoints.values.md ? 'auto' : '100%'
}
}, video ? /*#__PURE__*/React__default.createElement("video", {
src: video,
autoPlay: true,
loop: true,
muted: true,
style: _extends({
width: '100%',
height: '100%',
minWidth: '100%',
minHeight: '100%'
}, index !== 1 && {
opacity: 0.1
})
}) : /*#__PURE__*/React__default.createElement("img", {
src: image,
alt: title,
style: {
width: '100%',
height: '100%',
objectFit: "fill"
}
})), /*#__PURE__*/React__default.createElement(Grid, {
item: true,
xs: window.innerWidth < breakpoints.values.md ? 12 : image || video ? 5 : 12,
style: {
justifyContent: 'center',
alignItems: 'center',
height: '100%',
padding: image || video ? '20px 40px 20px 40px' : '40px 80px 40px 80px' // top right bottom left
}
}, /*#__PURE__*/React__default.createElement(Stack, {
spacing: 2,
direction: "column",
justifyContent: "space-between",
alignItems: "center",
style: {
height: '100%'
}
}, /*#__PURE__*/React__default.createElement(Stack, {
spacing: 2,
style: {
marginTop: 50
}
}, /*#__PURE__*/React__default.createElement(Typography, {
variant: "h5",
fontWeight: "bold",
letterSpacing: "-0.6px",
fontSize: "24px",
fontFamily: "Open Sans"
}, title), /*#__PURE__*/React__default.createElement(Typography, {
variant: "body2",
fontSize: "14px",
fontFamily: "Open Sans",
fontWeight: "medium",
style: {
whiteSpace: 'pre-line'
}
}, description)), actions && /*#__PURE__*/React__default.createElement(Box, {
style: {
width: '100%',
marginBottom: 20
}
}, actions)))))));
};
SliderItem.propTypes = {
id: PropTypes.string.isRequired,
onlyItem: PropTypes.bool.isRequired,
index: PropTypes.number.isRequired,
isHidden: PropTypes.bool,
video: PropTypes.string,
image: PropTypes.string,
title: PropTypes.string,
description: PropTypes.string,
actions: PropTypes.node,
calculateMinWidth: PropTypes.func.isRequired,
onClose: PropTypes.func.isRequired,
moveToASpecificItem: PropTypes.func.isRequired
};
SliderItem.defaultProps = {
isHidden: false,
onlyItem: false,
video: null,
image: null,
title: '',
description: '',
actions: null,
calculateMinWidth: function calculateMinWidth() {},
onClose: function onClose() {},
moveToASpecificItem: function moveToASpecificItem() {}
};
function ReactCardCarousel(_ref) {
var open = _ref.open,
onClose = _ref.onClose,
items = _ref.items;
var _useState = useState([]),
sliderItems = _useState[0],
setSliderItems = _useState[1];
var _useState2 = useState(0),
currentItem = _useState2[0],
setCurrentItem = _useState2[1];
var _useState3 = useState([]),
viewedItems = _useState3[0],
setViewedItems = _useState3[1];
useEffect(function () {
setSliderItems(items || []);
var itemsDeepCopy = [].concat(items); // Deep copy of items
// Set viewed sliderItems to 3
var currentViewedItems = [].concat(items && items.length > 1 ? [{
id: 0,
content: null,
isHidden: true
}] : [], itemsDeepCopy.slice(0, 2));
setViewedItems(currentViewedItems);
setCurrentItem(0);
}, []);
var moveToNext = function moveToNext() {
var itemsDeepCopy = [].concat(sliderItems); // Deep copy of items
if (viewedItems && !viewedItems[0].isHidden) {
var currentViewedItems = [].concat(itemsDeepCopy.slice(currentItem, currentItem + 3));
if (currentViewedItems.length < 3) {
currentViewedItems.push({
id: 0,
content: null,
isHidden: true
});
}
setViewedItems(currentViewedItems);
setCurrentItem(currentItem + 1);
} else {
var _currentViewedItems = [].concat(itemsDeepCopy.slice(0, 3));
if (_currentViewedItems.length < 3) {
_currentViewedItems.push({
id: 0,
content: null,
isHidden: true
});
}
setViewedItems(_currentViewedItems);
setCurrentItem(1);
}
};
var moveToPrevious = function moveToPrevious() {
var _viewedItems$;
var itemsDeepCopy = [].concat(sliderItems); // Deep copy of items
if (viewedItems && (_viewedItems$ = viewedItems[0]) != null && _viewedItems$.isHidden) {
var currentViewedItems = [].concat(itemsDeepCopy.slice(currentItem - 2, currentItem + 1));
if (currentViewedItems.length < 3) {
currentViewedItems.unshift({
id: 0,
content: null,
isHidden: true
});
}
setViewedItems(currentViewedItems);
setCurrentItem(currentItem - 1);
} else {
if (currentItem === 1) {
var _currentViewedItems2 = [{
id: 0,
content: null,
isHidden: true
}].concat(itemsDeepCopy.slice(0, 2));
if (_currentViewedItems2.length < 3) {
_currentViewedItems2.push({
id: 0,
content: null,
isHidden: true
});
}
setViewedItems(_currentViewedItems2);
setCurrentItem(currentItem - 1);
} else {
var _currentViewedItems3 = [].concat(itemsDeepCopy.slice(currentItem - 2, currentItem + 1));
if (_currentViewedItems3.length < 3) {
_currentViewedItems3.unshift({
id: 0,
content: null,
isHidden: true
});
}
setViewedItems(_currentViewedItems3);
setCurrentItem(currentItem - 1);
}
}
};
var isNextItemAvailable = function isNextItemAvailable() {
return currentItem < sliderItems.length - 1;
};
var isPreviousItemAvailable = function isPreviousItemAvailable() {
var _viewedItems$2;
if (viewedItems && (_viewedItems$2 = viewedItems[0]) != null && _viewedItems$2.isHidden) {
return currentItem > 1;
}
return currentItem > 0;
};
var calculateMinWidth = function calculateMinWidth() {
//currentWidth of screen
var width = window.innerWidth;
//calculate min width by 80% of current width
var minWidth = width * 0.8;
if (minWidth > 885) minWidth = 885;
if (minWidth < 765) minWidth = width - 80;
return minWidth + "px";
};
var moveToASpecificItem = function moveToASpecificItem(id) {
//find the index of the item
var index = sliderItems.findIndex(function (item) {
return item.id === id;
});
//if the item is not found, return
if (index === -1) return;
//if the item is already in the view, return
if (index === currentItem) return;
//if the item is in the next view
if (index > currentItem && index < currentItem + 3) {
//move to the next item
moveToNext();
return;
}
//if the item is in the previous view
else if (index < currentItem && index > currentItem - 3) {
//move to the previous item
moveToPrevious();
return;
} else {
var itemsDeepCopy = [].concat(sliderItems); // Deep copy of items
//Get item after the current item
var currentViewedItems = [itemsDeepCopy[index - 1] ? itemsDeepCopy[index - 1] : {
id: 0,
content: null,
isHidden: true
}, itemsDeepCopy[index], itemsDeepCopy[index + 1] ? itemsDeepCopy[index + 1] : {
id: 0,
content: null,
isHidden: true
}];
setViewedItems(currentViewedItems);
setCurrentItem(index);
}
};
return /*#__PURE__*/React__default.createElement(Dialog, {
fullScreen: true,
open: open,
onClose: onClose,
style: {
backgroundColor: "rgba(255, 255, 255, 0.5)",
backdropFilter: "blur( 5px )",
padding: 0,
margin: 0
},
PaperProps: {
style: {
backgroundColor: 'transparent',
boxShadow: 'none'
}
}
}, /*#__PURE__*/React__default.createElement(Box, {
id: "box1",
style: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '100vh',
overflow: 'hidden',
width: '100%',
backgroundColor: "transparent"
}
}, /*#__PURE__*/React__default.createElement(Stack, {
direction: "column",
spacing: 2
}, /*#__PURE__*/React__default.createElement(Box, {
id: "box2",
style: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '100vh',
overflow: 'hidden',
width: '100%',
backgroundColor: "transparent"
}
}, viewedItems.map(function (item, index) {
return /*#__PURE__*/React__default.createElement("div", {
key: item.id,
id: item.id
}, item.isHidden ? /*#__PURE__*/React__default.createElement("div", {
style: {
width: calculateMinWidth(),
minWidth: calculateMinWidth(),
height: '550px',
minHeight: '550px',
marginRight: '30px',
marginLeft: '30px'
}
}) : /*#__PURE__*/React__default.createElement(SliderItem, {
onlyItem: viewedItems.length === 1,
id: item.id,
index: index,
isHidden: item.isHidden,
video: item.video,
image: item.image,
title: item.title,
description: item.description,
actions: item.actions || null,
calculateMinWidth: calculateMinWidth,
onClose: onClose,
moveToASpecificItem: moveToASpecificItem
}));
})), /*#__PURE__*/React__default.createElement(SliderIndicator, {
sliderItems: sliderItems,
currentItem: currentItem,
moveToASpecificItem: moveToASpecificItem
})), /*#__PURE__*/React__default.createElement(SliderActions, {
isNextItemAvailable: isNextItemAvailable,
isPreviousItemAvailable: isPreviousItemAvailable,
moveToNext: moveToNext,
moveToPrevious: moveToPrevious
})));
}
ReactCardCarousel.defaultProps = {
open: false,
onClose: function onClose() {}
};
ReactCardCarousel.propTypes = {
open: PropTypes.bool,
onClose: PropTypes.func
};
var CardCarousel = function CardCarousel(_ref) {
var _ref$open = _ref.open,
open = _ref$open === void 0 ? false : _ref$open,
_ref$onClose = _ref.onClose,
onClose = _ref$onClose === void 0 ? function () {} : _ref$onClose,
_ref$items = _ref.items,
items = _ref$items === void 0 ? [] : _ref$items;
return /*#__PURE__*/createElement(ReactCardCarousel, {
open: open,
onClose: onClose,
items: items
});
};
CardCarousel.propTypes = {
open: PropTypes.bool,
onClose: PropTypes.func,
items: PropTypes.array
};
export { CardCarousel };
//# sourceMappingURL=react-card-carousel-materialui.esm.js.map