UNPKG

gatsby-image-background-slider

Version:

Lazy-loaded background images, with a simple fade transition between them, using gatsby-image. Inspired by react-background-slider, except for—well—the obvious.

339 lines (284 loc) 9.3 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var React = require('react'); var React__default = _interopDefault(React); var PropTypes = _interopDefault(require('prop-types')); var Img = _interopDefault(require('gatsby-image')); var _extends = Object.assign || 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; }; var objectWithoutProperties = function (obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }; var slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); /** * @param {object} props Component props * @param {object} props.callbacks interface for callback functions (pass this to Pagination, if used) * @param {(newIndex:number) => void} props.callbacks.atIndex sets background to specified index * @param {(prevIndex: number, newIndex: number) => void} props.callbacks.onChange user-provided callback fired when background image changes * @param {Function} props.callbacks.next sets background to the next one * @param {Function} props.callbacks.prev sets background to the previous one * @param {string[]} props.images list of specified image file names to set order * @param {number} [props.duration=5] duration background is shown for * @param {number} [props.transition=2] length of transition * @param {object.isRequired} props.query result of GraphQL query for images * @param {JSXElement[]} props.children subtitles/captions in sync for respective background images; * (<React.Fragment/> to skip over one) * @param {Array} props.gatsbyImageProps remaining props spread onto Img elements * @param {number} [props.initDelay=5] initial delay before first transition */ var BackgroundSlider = function BackgroundSlider(_ref) { var callbacks = _ref.callbacks, images = _ref.images, duration = _ref.duration, transition = _ref.transition, initDelay = _ref.initDelay, query = _ref.query, children = _ref.children, gatsbyImageProps = objectWithoutProperties(_ref, ['callbacks', 'images', 'duration', 'transition', 'initDelay', 'query', 'children']); var nodes = []; var bgRefs = []; var subRefs = []; var bgWrappers = []; var subWrappers = []; var style = gatsbyImageProps.style, imageProps = objectWithoutProperties(gatsbyImageProps, ['style']); nodes.safePush = function (data) { if (data) { return this.push(data); } else { return this.length; } }; if (images) { var _loop = function _loop(image) { nodes.safePush(query.backgrounds.nodes.find(function (node) { return node.relativePath === image; })); }; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = images[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var image = _step.value; _loop(image); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } } else { nodes = query.backgrounds.nodes; } var imgs = nodes.map(function (data, index) { var backgroundStyle = { position: "absolute", zIndex: -10, width: "100%", height: "100%", margin: 0, padding: "none", left: 0, top: 0, backgroundSize: "cover", opacity: index ? 0 : 1, transition: 'opacity ' + transition + 's' }; var subStyle = { opacity: index ? 0 : 1, transition: 'opacity ' + transition + 's', pointerEvents: index ? "none" : "auto" }; subRefs[index] = React__default.createRef(); bgRefs[index] = React__default.createRef(); return React__default.createElement( React__default.Fragment, { key: index }, React__default.createElement( 'div', { ref: bgRefs[index] }, React__default.createElement(Img, _extends({ fluid: data.childImageSharp.fluid, style: _extends({}, backgroundStyle, style) }, imageProps)) ), React__default.createElement( 'div', { ref: subRefs[index], style: subStyle }, React__default.Children.toArray(children)[index] ) ); }); var _useState = React.useState(0), _useState2 = slicedToArray(_useState, 2), timeoutHandle = _useState2[0], setTimeoutHandle = _useState2[1]; var timeoutHandleRef = React.useRef(timeoutHandle); timeoutHandleRef.current = timeoutHandle; var _useState3 = React.useState(0), _useState4 = slicedToArray(_useState3, 2), index = _useState4[0], setIndex = _useState4[1]; var indexRef = React.useRef(index); indexRef.current = index; if (callbacks) callbacks.getCount = function () { return imgs.length; }; var clearAndSetTimeoutHandle = function clearAndSetTimeoutHandle(newTimeoutHandle) { clearTimeout(timeoutHandleRef.current); setTimeoutHandle(newTimeoutHandle); }; var initEffect = function initEffect() { bgRefs.forEach(function (bgRef) { bgWrappers.push(bgRef.current.firstElementChild); }); subRefs.forEach(function (subRef) { subWrappers.push(subRef.current); }); var length = bgWrappers.length; var changeIndex = function changeIndex(newIndex) { var index = indexRef.current; clearTimeout(timeoutHandleRef.current); bgWrappers[index].style.opacity = 0; bgWrappers[newIndex % length].style.opacity = 1; subWrappers[index].style.opacity = 0; subWrappers[index].style.pointerEvents = "none"; subWrappers[newIndex % length].style.opacity = 1; subWrappers[newIndex % length].style.pointerEvents = "auto"; if (callbacks && callbacks.onChange) { callbacks.onChange(index, newIndex % length); } setIndex(newIndex % length); clearAndSetTimeoutHandle(setTimeout(callback, duration * 1000)); }; var callback = function callback() { var index = indexRef.current; changeIndex(index + 1); }; clearAndSetTimeoutHandle(setTimeout(callback, initDelay * 1000)); if (callbacks) { callbacks.atIndex = changeIndex; callbacks.next = function () { return callbacks.atIndex((indexRef.current + 1) % length); }; callbacks.prev = function () { return callbacks.atIndex((indexRef.current + length - 1) % length); }; } return function () { clearTimeout(timeoutHandleRef.current); }; }; // Runs once after DOM is loaded; effectively `componentDidMount` React.useEffect(initEffect, []); return React__default.createElement( React__default.Fragment, null, imgs ); }; BackgroundSlider.defaultProps = { images: null, duration: 5, transition: 2, initDelay: 5 }; BackgroundSlider.propTypes = { query: PropTypes.object.isRequired, images: PropTypes.arrayOf(PropTypes.string), duration: PropTypes.number, transition: PropTypes.number, initDelay: PropTypes.number }; var Pagination = function Pagination(_ref2) { var callbacks = _ref2.callbacks; var buttonRefs = []; React.useEffect(function () { callbacks.onChange = function (prevIndex, newIndex) { buttonRefs[prevIndex].current.style.color = 'silver'; buttonRefs[prevIndex].current.style.transform = 'scale(1.0,1.0)'; buttonRefs[newIndex].current.style.color = 'white'; buttonRefs[newIndex].current.style.transform = "scale(1.2, 1.2)"; }; }, []); return React__default.createElement( React__default.Fragment, null, Array.from(Array(callbacks.getCount()).keys()).map(function (index) { return React__default.createElement( 'span', { role: 'button', ref: buttonRefs[index] = React__default.createRef(), key: index, style: { userSelect: 'none', color: index === 0 ? 'white' : 'silver', fontSize: '4em', cursor: 'pointer', display: 'inline-block', transform: index === 0 ? 'scale(1.2,1.2)' : 'scale(1.0)' }, onClick: function onClick() { return callbacks.atIndex(index); } }, '\xB7' ); }) ); }; exports.default = BackgroundSlider; exports.Pagination = Pagination; //# sourceMappingURL=index.js.map