UNPKG

instagram-story

Version:

Instagram story UI build in ReactJS

343 lines (292 loc) 9.98 kB
import PropTypes from 'prop-types'; import React, { memo, useEffect, useState } from 'react'; function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _iterableToArrayLimit(arr, i) { if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; 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"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function addStyles(selector, styles, id) { if (styles.length) { var _styleSheet$cssRules; var style = document.createElement('style'); style.id = id; document.head.appendChild(style); var styleSheet = style.sheet; styleSheet.insertRule("".concat(selector, " { ").concat(styles, " }"), styleSheet === null || styleSheet === void 0 ? void 0 : (_styleSheet$cssRules = styleSheet.cssRules) === null || _styleSheet$cssRules === void 0 ? void 0 : _styleSheet$cssRules.length); } } function removeElement(selector) { var element = document.querySelector(selector); if (element) element.remove(); } var Timeline = function Timeline(props) { var animationIndex = props.animationIndex, count = props.count, align = props.align, onCarouselIndexChange = props.onCarouselIndexChange, delay = props.delay; var handleAnimationEnd = function handleAnimationEnd() { var newIndex = animationIndex + 1; onCarouselIndexChange(newIndex); }; useEffect(function () { var delayInSecs = delay / 1000; var timelineStyle = "\n\t\t\tcontent: '';\n\t\t\twidth: 100%;\n\t\t\theight: 2px;\n\t\t\tdisplay: block;\n\t\t\tbackground-color: #fff;\n\t\t\ttransform-origin: 0% center 0px;\n\t\t\tanimation: loader ".concat(delayInSecs, "s linear;\n\t\t"); var fillStyle = 'background-color: #fff !important;'; var loaderAnimation = " \n\t\t\t0% {\n\t\t\t\ttransform: scaleX(0);\n\t\t\t }\n\t\t\t 100% {\n\t\t\t \ttransform: scaleX(1);\n\t\t\t }\n\t\t"; addStyles('.__active::after', timelineStyle, 'js-insta-story-plugin-active'); addStyles('.__fill', fillStyle, 'js-insta-story-plugin-fill'); addStyles('@keyframes loader', loaderAnimation, 'js-insta-story-plugin-animation'); return function () { removeElement('js-insta-story-plugin-fill'); removeElement('js-insta-story-plugin-active'); removeElement('js-insta-story-plugin-animation'); }; }, [delay]); var renderElements = function renderElements() { var elements = []; for (var i = 0; i < count; i++) { var className = ''; if (i < animationIndex) { className = '__fill'; } else if (i === animationIndex) { className = '__active'; } // Styling the div's var elementStyle = { flex: '1 0', height: '2px', margin: '5px', backgroundColor: '#999' }; var element = /*#__PURE__*/React.createElement("div", { key: i, style: elementStyle, className: className, "data-testid": "timeline-".concat(i), onAnimationEnd: handleAnimationEnd }); elements.push(element); } return elements; }; var alignContainer = _objectSpread2({}, align === 'top' ? { top: '0' } : { bottom: '0' }); var timelineStyle = _objectSpread2({ width: 'inherit', position: 'fixed' }, alignContainer); var timelineArticleStyle = { width: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center' }; return /*#__PURE__*/React.createElement("section", { style: timelineStyle, "data-testid": "timeline-root" }, /*#__PURE__*/React.createElement("article", { style: timelineArticleStyle }, renderElements())); }; Timeline.propTypes = { delay: PropTypes.string.isRequired, align: PropTypes.string.isRequired, count: PropTypes.number.isRequired, onCarouselIndexChange: PropTypes.func.isRequired, animationIndex: PropTypes.number.isRequired }; var Timeline$1 = memo(Timeline); var StorySlider = function StorySlider(_ref) { var pivot = _ref.pivot, children = _ref.children, imageWidth = _ref.imageWidth; var newChildren = React.Children.map(children, function (child, index) { var style = { position: 'absolute' }; if (index < pivot) { style.left = "-".concat(Math.abs(index - pivot) * parseInt(imageWidth, 10), "px"); } else if (index === pivot) { style.left = '0'; } else { style.left = "".concat(Math.abs(index - pivot) * parseInt(imageWidth, 10), "px"); } return React.cloneElement(child, { style: style }); }); var sliderSectionStyle = { width: 'inherit', overflow: 'hidden', whiteSpace: 'nowrap' }; return /*#__PURE__*/React.createElement("article", { style: sliderSectionStyle }, newChildren); }; StorySlider.propTypes = { pivot: PropTypes.number.isRequired, children: PropTypes.node.isRequired, imageWidth: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired }; var StorySlider$1 = memo(StorySlider); function detectImageDimensions(imgURL) { var img = document.createElement('img'); img.src = imgURL; return new Promise(function (resolve) { var poll = setInterval(function () { if (img.naturalWidth) { clearInterval(poll); } return resolve({ width: img.naturalWidth, height: img.naturalHeight }); }, 10); }); } var Story = function Story(props) { var children = props.children, delay = props.delay, getCurrentSlideIndex = props.getCurrentSlideIndex, imageWidth = props.imageWidth, _props$timelineAlign = props.timelineAlign, timelineAlign = _props$timelineAlign === void 0 ? 'bottom' : _props$timelineAlign; var imageCount = React.Children.count(children); var _useState = useState(imageWidth), _useState2 = _slicedToArray(_useState, 2), width = _useState2[0], setWidth = _useState2[1]; var _useState3 = useState(0), _useState4 = _slicedToArray(_useState3, 2), idx = _useState4[0], setIdx = _useState4[1]; useEffect(function () { if (width === 0) { detectImageDimensions(children[0].props.src).then(function (res) { setWidth(res.width); }); } }, [children, width]); var onCarouselIndexChange = function onCarouselIndexChange() { if (idx < imageCount - 1) { setIdx(idx + 1); } }; // Call `getCurrentSlideIndex` to notify updated slide index getCurrentSlideIndex(idx); var storyContainerStyle = { width: 'inherit', height: 'inherit', overflow: 'hidden', position: 'relative' }; return /*#__PURE__*/React.createElement("section", { style: storyContainerStyle }, /*#__PURE__*/React.createElement(StorySlider$1, { imageWidth: width, pivot: idx }, children), /*#__PURE__*/React.createElement(Timeline$1, { delay: delay, count: imageCount, animationIndex: idx, align: timelineAlign, onCarouselIndexChange: onCarouselIndexChange })); }; Story.defaultProps = { timelineAlign: 'top', getCurrentSlideIndex: function getCurrentSlideIndex() {} }; Story.propTypes = { timelineAlign: PropTypes.string, delay: PropTypes.string.isRequired, getCurrentSlideIndex: PropTypes.func, imageWidth: PropTypes.string.isRequired, children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired }; var Story$1 = memo(Story); export default Story$1;