UNPKG

@cloudscape_innovation/react-images-viewer

Version:
472 lines (466 loc) 19.5 kB
"use strict"; function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _propTypes = _interopRequireDefault(require("prop-types")); var _react = _interopRequireWildcard(require("react")); var _aphrodite = require("aphrodite"); var _reactScrolllock = _interopRequireDefault(require("react-scrolllock")); var _theme = _interopRequireDefault(require("./theme")); var _Arrow = _interopRequireDefault(require("./components/Arrow")); var _Container = _interopRequireDefault(require("./components/Container")); var _Footer = _interopRequireDefault(require("./components/Footer")); var _Header = _interopRequireDefault(require("./components/Header")); var _PaginatedThumbnails = _interopRequireDefault(require("./components/PaginatedThumbnails")); var _Portal = _interopRequireDefault(require("./components/Portal")); var _Spinner = _interopRequireDefault(require("./components/Spinner")); var _util = require("./utils/util"); var _jsxRuntime = require("react/jsx-runtime"); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(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 (var _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); } function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); } function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); } function _possibleConstructorReturn(t, e) { if (e && ("object" == _typeof(e) || "function" == typeof e)) return e; if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined"); return _assertThisInitialized(t); } function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); } function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: !0, configurable: !0 } }), Object.defineProperty(t, "prototype", { writable: !1 }), e && _setPrototypeOf(t, e); } function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); } function normalizeSourceSet(data) { var sourceSet = data.srcSet || data.srcset; if (Array.isArray(sourceSet)) { return sourceSet.join(); } return sourceSet; } var ThemeContext = /*#__PURE__*/(0, _react.createContext)({ theme: _theme.default, toggleTheme: function toggleTheme(newTheme) {} }); var ImgsViewer = /*#__PURE__*/function (_Component) { function ImgsViewer(props) { var _this; _classCallCheck(this, ImgsViewer); _this = _callSuper(this, ImgsViewer, [props]); _this.theme = (0, _util.deepMerge)(_theme.default, _this.props.theme); _this.classes = _aphrodite.StyleSheet.create((0, _util.deepMerge)(defaultStyles, _this.props.theme)); _this.toggleTheme = function (theme) { _this.setState(function () { return { theme: theme }; }); }; _this.state = { imgLoaded: false, theme: _this.theme, toggleTheme: _this.toggleTheme }; _util.bindFunctions.call(_this, ["gotoNext", "gotoPrev", "closeBackdrop", "handleKeyboardInput", "handleImgLoaded"]); return _this; } _inherits(ImgsViewer, _Component); return _createClass(ImgsViewer, [{ key: "componentDidMount", value: function componentDidMount() { if (this.props.isOpen) { if (this.props.enableKeyboardInput) { window.addEventListener("keydown", this.handleKeyboardInput); } if (typeof this.props.currImg === "number") { this.preloadImg(this.props.currImg, this.handleImgLoaded); } } } }, { key: "componentDidUpdate", value: function componentDidUpdate(prevProps) { if (!_util.canUseDom) return; // always to preload imgs with both directions // then when user changs direction, img also show quickly if (this.props.preloadNextImg) { var nextIdx = this.props.currImg + 1; var prevIdx = this.props.currImg - 1; this.preloadImg(prevIdx); this.preloadImg(nextIdx); } // preload currImg if (prevProps.currImg !== this.props.currImg || !prevProps.isOpen && this.props.isOpen) { var img = this.preloadImgData(this.props.imgs[this.props.currImg], this.handleImgLoaded); if (img) this.setState({ imgLoaded: img.complete }); } // add/remove event listeners if (!prevProps.isOpen && this.props.isOpen && this.props.enableKeyboardInput) { window.addEventListener("keydown", this.handleKeyboardInput); } if (!this.props.isOpen && this.props.enableKeyboardInput) { window.removeEventListener("keydown", this.handleKeyboardInput); } } }, { key: "componentWillUnmount", value: function componentWillUnmount() { if (this.props.enableKeyboardInput) { window.removeEventListener("keydown", this.handleKeyboardInput); } } // ==================== // Methods // ==================== }, { key: "preloadImg", value: function preloadImg(idx, onload) { return this.preloadImgData(this.props.imgs[idx], onload); } }, { key: "preloadImgData", value: function preloadImgData(data, onload) { if (!data) return; var img = new Image(); var sourceSet = normalizeSourceSet(data); // Todo: add error handling for missing imgs img.onerror = onload; img.onload = onload; img.src = data.src; if (sourceSet) img.srcset = sourceSet; return img; } }, { key: "gotoNext", value: function gotoNext(event) { var _this$props = this.props, currImg = _this$props.currImg, imgs = _this$props.imgs; var imgLoaded = this.state.imgLoaded; if (!imgLoaded || currImg === imgs.length - 1) return; if (event) { event.preventDefault(); event.stopPropagation(); } this.props.onClickNext(); } }, { key: "gotoPrev", value: function gotoPrev(event) { var currImg = this.props.currImg; var imgLoaded = this.state.imgLoaded; if (!imgLoaded || currImg === 0) return; if (event) { event.preventDefault(); event.stopPropagation(); } this.props.onClickPrev(); } }, { key: "closeBackdrop", value: function closeBackdrop(event) { if (event.target.id === "viewerBackdrop" || event.target.tagName === "FIGURE") { this.props.onClose(); } } }, { key: "handleKeyboardInput", value: function handleKeyboardInput(event) { var keyCode = event.keyCode; if (keyCode === 37 || keyCode === 33 || keyCode === 38) { // left, pageup, up this.gotoPrev(event); return true; } else if (keyCode === 39 || keyCode === 34 || keyCode === 40) { // right, pagedown, down this.gotoNext(event); return true; } else if (keyCode === 27 || keyCode === 32) { // esc, space this.props.onClose(); return true; } return false; } }, { key: "handleImgLoaded", value: function handleImgLoaded() { this.setState({ imgLoaded: true }); } // ==================== // Renderers // ==================== }, { key: "renderArrowPrev", value: function renderArrowPrev(theme) { if (this.props.currImg === 0) return null; return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Arrow.default, { theme: theme, direction: "left", icon: "arrowLeft", onClick: this.gotoPrev, title: this.props.leftArrowTitle, type: "button" }); } }, { key: "renderArrowNext", value: function renderArrowNext(theme) { if (this.props.currImg === this.props.imgs.length - 1) return null; return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Arrow.default, { theme: theme, direction: "right", icon: "arrowRight", onClick: this.gotoNext, title: this.props.rightArrowTitle, type: "button" }); } }, { key: "renderDialog", value: function renderDialog(newState) { var _this2 = this; var _this$props2 = this.props, backdropCloseable = _this$props2.backdropCloseable, isOpen = _this$props2.isOpen, showThumbnails = _this$props2.showThumbnails, width = _this$props2.width; var imgLoaded = this.state.imgLoaded; if (!isOpen) return /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {}, "closed"); var offsetThumbnails = showThumbnails ? this.theme.thumbnail.size + this.theme.container.gutter.vertical : 0; return /*#__PURE__*/(0, _jsxRuntime.jsx)(ThemeContext.Consumer, { children: function children(_ref) { var theme = _ref.theme, toggleTheme = _ref.toggleTheme; theme = newState.theme; return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Container.default, { theme: theme, onClick: backdropCloseable && _this2.closeBackdrop, onTouchEnd: backdropCloseable && _this2.closeBackdrop, children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_react.Fragment, { children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { className: (0, _aphrodite.css)(_this2.classes.content), style: { marginBottom: offsetThumbnails, maxWidth: width }, children: [imgLoaded && _this2.renderHeader(theme), " ", _this2.renderImgs(theme), _this2.renderSpinner(), " ", imgLoaded && _this2.renderFooter(theme)] }), imgLoaded && _this2.renderThumbnails(theme), imgLoaded && _this2.renderArrowPrev(theme), imgLoaded && _this2.renderArrowNext(theme), _this2.props.preventScroll && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactScrolllock.default, {})] }) }, "open"); } }); } }, { key: "renderImgs", value: function renderImgs(theme) { var _this$props3 = this.props, currImg = _this$props3.currImg, imgs = _this$props3.imgs, onClickImg = _this$props3.onClickImg, showThumbnails = _this$props3.showThumbnails; var imgLoaded = this.state.imgLoaded; if (!imgs || !imgs.length) return null; var img = imgs[currImg]; var sourceSet = normalizeSourceSet(img); var sizes = sourceSet ? "100vw" : null; var thumbnailsSize = showThumbnails ? theme.thumbnail.size : 0; var heightOffset = "".concat(theme.header.height + theme.footer.height + thumbnailsSize + theme.container.gutter.vertical, "px"); return /*#__PURE__*/(0, _jsxRuntime.jsx)("figure", { className: (0, _aphrodite.css)(this.classes.figure), children: /*#__PURE__*/(0, _jsxRuntime.jsx)("img", { className: (0, _aphrodite.css)(this.classes.img, imgLoaded && this.classes.imgLoaded), onClick: onClickImg, sizes: sizes, alt: img.alt, src: img.src, srcSet: sourceSet, style: { cursor: onClickImg ? "pointer" : "auto", maxHeight: "calc(100vh - ".concat(heightOffset) } }) }); } }, { key: "renderThumbnails", value: function renderThumbnails(theme) { var _this$props4 = this.props, imgs = _this$props4.imgs, currImg = _this$props4.currImg, leftArrowTitle = _this$props4.leftArrowTitle, rightArrowTitle = _this$props4.rightArrowTitle, onClickThumbnail = _this$props4.onClickThumbnail, showThumbnails = _this$props4.showThumbnails, thumbnailOffset = _this$props4.thumbnailOffset; if (!showThumbnails) return null; return /*#__PURE__*/(0, _jsxRuntime.jsx)(_PaginatedThumbnails.default, { theme: theme, leftTitle: leftArrowTitle, rightTitle: rightArrowTitle, currImg: currImg, imgs: imgs, offset: thumbnailOffset, onClickThumbnail: onClickThumbnail }); } }, { key: "renderHeader", value: function renderHeader(theme) { var _this$props5 = this.props, closeBtnTitle = _this$props5.closeBtnTitle, customControls = _this$props5.customControls, onClose = _this$props5.onClose, showCloseBtn = _this$props5.showCloseBtn; return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Header.default, { theme: theme, customControls: customControls, onClose: onClose, showCloseBtn: showCloseBtn, closeBtnTitle: closeBtnTitle }); } }, { key: "renderFooter", value: function renderFooter(theme) { var _this$props6 = this.props, currImg = _this$props6.currImg, imgs = _this$props6.imgs, imgCountSeparator = _this$props6.imgCountSeparator, showImgCount = _this$props6.showImgCount; if (!imgs || !imgs.length) return null; return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Footer.default, { theme: theme, caption: imgs[currImg].caption, countCurr: currImg + 1, countSeparator: imgCountSeparator, countTotal: imgs.length, showCount: showImgCount }); } }, { key: "renderSpinner", value: function renderSpinner() { var _this$props7 = this.props, spinner = _this$props7.spinner, spinnerDisabled = _this$props7.spinnerDisabled, spinnerColor = _this$props7.spinnerColor, spinnerSize = _this$props7.spinnerSize; var imgLoaded = this.state.imgLoaded; var Spinner = spinner; if (spinnerDisabled) return null; return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { className: (0, _aphrodite.css)(this.classes.spinner, !imgLoaded && this.classes.spinnerActive), children: /*#__PURE__*/(0, _jsxRuntime.jsx)(Spinner, { color: spinnerColor, size: spinnerSize }) }); } }, { key: "render", value: function render() { return /*#__PURE__*/(0, _jsxRuntime.jsx)(ThemeContext.Provider, { value: this.state, children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Portal.default, { children: [" ", this.renderDialog(this.state), " "] }) }); } }]); }(_react.Component); ImgsViewer.propTypes = { backdropCloseable: _propTypes.default.bool, closeBtnTitle: _propTypes.default.string, currImg: _propTypes.default.number, customControls: _propTypes.default.arrayOf(_propTypes.default.node), enableKeyboardInput: _propTypes.default.bool, imgCountSeparator: _propTypes.default.string, imgs: _propTypes.default.arrayOf(_propTypes.default.shape({ src: _propTypes.default.string.isRequired, srcSet: _propTypes.default.oneOfType([_propTypes.default.array, _propTypes.default.string]), caption: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.element]), thumbnail: _propTypes.default.string })).isRequired, isOpen: _propTypes.default.bool, leftArrowTitle: _propTypes.default.string, onClickImg: _propTypes.default.func, onClickNext: _propTypes.default.func, onClickPrev: _propTypes.default.func, onClickThumbnail: _propTypes.default.func, onClose: _propTypes.default.func.isRequired, preloadNextImg: _propTypes.default.bool, preventScroll: _propTypes.default.bool, rightArrowTitle: _propTypes.default.string, showCloseBtn: _propTypes.default.bool, showImgCount: _propTypes.default.bool, showThumbnails: _propTypes.default.bool, spinnerDisabled: _propTypes.default.bool, spinner: _propTypes.default.func, spinnerColor: _propTypes.default.string, spinnerSize: _propTypes.default.number, theme: _propTypes.default.object, thumbnailOffset: _propTypes.default.number, width: _propTypes.default.number }; ImgsViewer.defaultProps = { currImg: 0, enableKeyboardInput: true, imgCountSeparator: " / ", onClickShowNextImg: true, preloadNextImg: true, preventScroll: true, showCloseBtn: true, showImgCount: true, spinnerDisabled: false, spinner: _Spinner.default, spinnerColor: "#fff", spinnerSize: 50, theme: {}, thumbnailOffset: 2, width: 1024 }; var defaultStyles = { content: { position: "relative" }, figure: { margin: 0 // remove browser default }, img: { display: "block", // removes browser default gutter height: "auto", margin: "0 auto", // main center on very short screens or very narrow img maxWidth: "100%", // disable user select WebkitTouchCallout: "none", userSelect: "none", // opacity animation on image load opacity: 0, transition: "opacity .3s" }, imgLoaded: { opacity: 1 }, spinner: { position: "absolute", top: "50%", left: "50%", transform: "translate(-50%, -50%)", // opacity animation to make spinner appear with delay opacity: 0, transition: "opacity .3s", pointerEvents: "none" }, spinnerActive: { opacity: 1 } }; var _default = exports.default = ImgsViewer;