@momentum-ui/react-collaboration
Version:
Cisco Momentum UI Framework for React Collaboration Applications
378 lines • 22.6 kB
JavaScript
/** @component lightbox */
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
import React from 'react';
import PropTypes from 'prop-types';
import Modal from 'react-aria-modal';
import { Icon } from '@momentum-ui/react-collaboration';
import ButtonSimple from '../../components/ButtonSimple';
import TooltipNext from '../../components/Tooltip';
import IconNext from '../../components/Icon';
import MomentumThemeProvider from '../../components/ThemeProvider';
import LoadingSpinner from '../../components/LoadingSpinner';
import { THEME_NAMES } from '../../components/ThemeProvider/ThemeProvider.constants';
import { v4 as uuidv4 } from 'uuid';
/**
* @deprecated - Components in the legacy folder (/src/legacy) are deprecated. Please use a component from the components folder (/src/components) instead. Legacy components may not follow accessibility standards.
**/
var Lightbox = /** @class */ (function (_super) {
__extends(Lightbox, _super);
function Lightbox(props) {
var _this = _super.call(this, props) || this;
_this.state = {
viewportDimensions: {
width: 600,
height: 600,
},
zoom: 1,
};
_this.handleResize = function () {
var viewport = _this.viewport;
_this.setState({
viewportDimensions: {
width: viewport.offsetWidth,
height: viewport.offsetHeight,
},
});
};
_this.handleKeyDown = function (e) {
var _a = _this.props, index = _a.index, pages = _a.pages;
var newIndex;
switch (e.keyCode) {
// Escape
case 27:
_this.handleClose();
return;
// left arrow & up arrow
case 37:
case 38:
newIndex = Math.max(index - 1, 0);
break;
// right arrow & down arrow
case 39:
case 40:
newIndex = Math.min(index + 1, pages.length - 1);
break;
// page up & home
case 33:
case 36:
newIndex = 0;
break;
// page down & end
case 34:
case 35:
newIndex = pages.length - 1;
break;
// 1 - 9
case 49:
case 50:
case 51:
case 52:
case 53:
case 54:
case 55:
case 56:
case 57:
newIndex = Math.min(e.keyCode - 49, pages.length - 1);
break;
default:
return;
}
_this.triggerPageChange(newIndex, e, true);
};
_this.handleThumbnailClick = function (index) {
var onChange = _this.props.onChange;
onChange && onChange(index);
};
_this.triggerPageChange = function (index, e, needFocus) {
var _a = _this.props, onChange = _a.onChange, pages = _a.pages;
var target = _this.lightBox && _this.lightBox.querySelector("[data-index=\"".concat(index, "\"]"));
if (index >= 0 && index <= pages.length - 1) {
onChange && onChange(index);
}
e.stopPropagation();
target && target.scrollIntoViewIfNeeded && target.scrollIntoViewIfNeeded();
target && needFocus && target.parentElement.focus();
};
_this.stopPropagation = function (e) {
e.stopPropagation();
};
_this.setZoom = function (increment) {
var newZoom = _this.state.zoom + increment;
_this.setState({
zoom: newZoom < 0.25 ? 0.25 : newZoom,
});
};
_this.handleDownload = function () {
var onDownload = _this.props.onDownload;
onDownload && onDownload();
};
_this.handleClose = function () {
var onClose = _this.props.onClose;
onClose && onClose();
};
_this.nameId = uuidv4();
return _this;
}
Lightbox.prototype.componentDidMount = function () {
window.addEventListener('keydown', this.handleKeyDown, true);
window.addEventListener('resize', this.handleResize, true);
var viewport = this.viewport;
if (viewport && viewport.clientWidth && viewport.clientHeight) {
// eslint-disable-next-line react/no-did-mount-set-state
this.setState({
viewportDimensions: {
width: viewport.clientWidth,
height: viewport.clientHeight,
},
});
}
};
Lightbox.prototype.componentDidUpdate = function (prevProps) {
if (prevProps.index !== this.props.index && this.state.zoom > 1 && this.imgWrapper) {
var viewportNode = this.viewport;
viewportNode.scrollTop = 0;
viewportNode.scrollLeft = (this.imgWrapper.offsetWidth - viewportNode.offsetWidth) / 2;
}
};
Lightbox.prototype.componentWillUnmount = function () {
window.removeEventListener('keydown', this.handleKeyDown, true);
window.removeEventListener('resize', this.handleResize, true);
};
Lightbox.prototype.render = function () {
var _this = this;
var _a = this.props, pages = _a.pages, index = _a.index, width = _a.width, height = _a.height, tooltips = _a.tooltips, downloading = _a.downloading, info = _a.info, name = _a.name, applicationId = _a.applicationId, imgClassName = _a.imgClassName, isImageRotated = _a.isImageRotated;
var _b = this.state, zoom = _b.zoom, viewportDimensions = _b.viewportDimensions;
var currentPage = pages[index];
var showColumn = pages.length > 1;
var LightThemeStyle = this.props.theme === THEME_NAMES.LIGHT_WEBEX
? { color: 'var(--mds-color-theme-text-primary-normal)' }
: {};
var calculateAspectRatioFit = function (srcWidth, srcHeight, maxWidth, maxHeight) {
var maxW, maxH;
if (isImageRotated) {
maxW = maxHeight;
maxH = maxWidth;
}
else {
maxW = maxWidth;
maxH = maxHeight;
}
var ratio = Math.min(maxW / srcWidth, maxH / srcHeight, 1);
return {
width: Math.round(srcWidth * ratio),
height: Math.round(srcHeight * ratio),
ratio: ratio,
};
};
var getThumbnails = function () {
var thumbnails = pages.map(function (page, idx) {
var key = "".concat(idx, ":").concat(page.thumb);
var body;
if (page.decrypting) {
var scale = width / 150;
var scaleY = height / scale;
var style = {
height: Math.round(scaleY),
};
key += ':decrypting';
body = (React.createElement("div", { className: "md-lightbox__thumbnail" +
"".concat((!!page.decrypting && " md-lightbox__thumbnail--decrypting") || ''), "data-index": idx, style: style },
React.createElement(Icon, { className: "md-lightbox__thumbnail--icon", name: "secure_28" })));
}
else {
body = (React.createElement("img", { alt: name, className: "md-lightbox__thumbnail" +
"".concat((!!page.decrypting && " md-lightbox__thumbnail--decrypting") || ''), "data-index": idx, draggable: "false", onDragStart: function () { return false; }, src: page.thumb }));
}
return (React.createElement("div", { className: 'md-lightbox__thumbnail-wrapper' +
"".concat((idx === index && " md-lightbox__thumbnail-wrapper--selected") || ''), key: key, onClick: function () { return _this.handleThumbnailClick(idx); }, onKeyPress: function () { return _this.handleThumbnailClick(idx); }, role: "tab", tabIndex: "0", "aria-selected": idx === index ? true : false },
body,
React.createElement("div", null, idx + 1)));
});
return React.createElement("div", { className: "md-lightbox__list" }, thumbnails);
};
var newWidth = width;
var newHeight = height;
var getViewport = function () {
var viewport;
var imageContainerStyles;
if (currentPage.content) {
if (currentPage.fullView) {
imageContainerStyles = {
width: '100%',
height: '100%',
overflow: 'hidden',
};
}
viewport = (React.createElement("div", { className: "md-lightbox__viewport-content", draggable: "false", onClick: _this.stopPropagation, onKeyPress: _this.stopPropagation, onDoubleClick: function () { return _this.setZoom(0.25); }, onDragStart: function () { return false; }, role: "button", tabIndex: "0" }, currentPage.content));
}
else if (currentPage.image) {
if (zoom <= 1) {
var dimensions = calculateAspectRatioFit(width * zoom, height * zoom, viewportDimensions.width, viewportDimensions.height);
newHeight = dimensions.height;
newWidth = dimensions.width;
imageContainerStyles = {
width: "".concat(dimensions.width, "px"),
height: "".concat(dimensions.height, "px"),
};
/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
viewport = (React.createElement("img", { alt: name, className: 'md-lightbox__viewport-image' + "".concat((imgClassName && " ".concat(imgClassName)) || ''), draggable: "false", onClick: _this.stopPropagation, onKeyPress: _this.stopPropagation, onDoubleClick: function () { return _this.setZoom(0.25); }, onDragStart: function () { return false; }, src: currentPage.image }));
}
else {
var dimensions = calculateAspectRatioFit(width, height, viewportDimensions.width, viewportDimensions.height);
imageContainerStyles = {};
newHeight = dimensions.height * zoom;
newWidth = dimensions.width * zoom;
viewport = (React.createElement("img", { alt: name, className: 'md-lightbox__viewport-image' + "".concat((imgClassName && " ".concat(imgClassName)) || ''), draggable: "false", onClick: _this.stopPropagation, onKeyPress: _this.stopPropagation, onDoubleClick: function () { return _this.setZoom(0.25); }, onDragStart: function () { return false; }, src: currentPage.image, style: {
maxHeight: newHeight,
maxWidth: newWidth,
minHeight: newHeight,
minWidth: newWidth,
} }));
}
}
return (React.createElement("div", { className: "md-lightbox__viewport-wrapper", ref: function (ref) { return (_this.imgWrapper = ref); }, style: imageContainerStyles }, viewport));
};
var leftArrowControl = (React.createElement(TooltipNext, { style: LightThemeStyle, type: "label", placement: "right", triggerComponent: React.createElement(ButtonSimple, { className: "md-lightbox__page-control md-lightbox__page-control-icon md-lightbox__page-controls--left", onPress: function (e) { return _this.triggerPageChange(index - 1, e); } },
React.createElement(IconNext, { name: "arrow-left", fillColor: "var(--mds-color-theme-common-text-primary-normal)", scale: 16 })) }, tooltips.previous));
var rightArrowControl = (React.createElement(TooltipNext, { style: LightThemeStyle, type: "label", placement: "left", triggerComponent: React.createElement(ButtonSimple, { className: "md-lightbox__page-control md-lightbox__page-control-icon md-lightbox__page-controls--right", onPress: function (e) { return _this.triggerPageChange(index + 1, e); } },
React.createElement(IconNext, { name: "arrow-right", fillColor: "var(--mds-color-theme-common-text-primary-normal)", scale: 16 })) }, tooltips.next));
var viewportControls = function () {
var downloadButton = (React.createElement(TooltipNext, { style: LightThemeStyle, type: "label", placement: "top", triggerComponent: React.createElement(ButtonSimple, { className: "md-lightbox__control md-lightbox__control-download", onPress: _this.handleDownload }, downloading ? (React.createElement(LoadingSpinner, { "aria-hidden": true })) : (React.createElement(IconNext, { name: "download", fillColor: "var(--mds-color-theme-common-text-primary-normal)", scale: 20, weight: "light" }))) }, downloading ? tooltips.downloading : tooltips.download));
var controlStyle = currentPage.content
? {
visibility: 'hidden',
}
: {};
var pageControl = pages.length > 1 ? (React.createElement("div", { className: "md-lightbox__controls md-lightbox__controls--center" },
React.createElement(TooltipNext, { style: LightThemeStyle, type: "label", placement: "top", triggerComponent: React.createElement(ButtonSimple, { className: "md-lightbox__control md-lightbox__control-left", onPress: function (e) { return _this.triggerPageChange(index - 1, e); } },
React.createElement(IconNext, { name: "arrow-left", fillColor: "var(--mds-color-theme-common-text-primary-normal)", scale: 20, weight: "light" })) }, tooltips.previous),
React.createElement("span", { className: "md-lightbox__control-value" }, "".concat(index + 1, " / ").concat(pages.length)),
React.createElement(TooltipNext, { style: LightThemeStyle, type: "label", placement: "top", triggerComponent: React.createElement(ButtonSimple, { className: "md-lightbox__control md-lightbox__control-right", onPress: function (e) { return _this.triggerPageChange(index + 1, e); } },
React.createElement(IconNext, { name: "arrow-right", fillColor: "var(--mds-color-theme-common-text-primary-normal)", scale: 20, weight: "light" })) }, tooltips.next))) : (React.createElement("div", { className: "md-lightbox__controls" },
React.createElement("span", { className: "md-lightbox__control-value" }, index + 1)));
return (React.createElement("div", { className: "md-lightbox__viewer-controls", onClick: _this.stopPropagation, onKeyPress: _this.stopPropagation, role: "group" },
React.createElement("div", { className: "md-lightbox__controls", style: controlStyle },
React.createElement(TooltipNext, { style: LightThemeStyle, type: "label", placement: "top", triggerComponent: React.createElement(ButtonSimple, { className: "md-lightbox__control", "data-test": "zoom-out-button", onPress: function () { return _this.setZoom(-0.25); } },
React.createElement(IconNext, { name: "zoom-out", fillColor: "var(--mds-color-theme-common-text-primary-normal)", scale: 20, weight: "light" })) }, tooltips.zoomOut),
React.createElement("span", { className: "md-lightbox__control-value md-lightbox__control-zoom-level" }, "".concat(Math.round(((newHeight * 1.0) / height) * 100), "%")),
React.createElement(TooltipNext, { style: LightThemeStyle, type: "label", placement: "top", triggerComponent: React.createElement(ButtonSimple, { className: "md-lightbox__control", "data-test": "zoom-in-button", onPress: function () { return _this.setZoom(0.25); } },
React.createElement(IconNext, { name: "zoom-in", fillColor: "var(--mds-color-theme-common-text-primary-normal)", scale: 20, weight: "light" })) }, tooltips.zoomIn)),
pageControl,
_this.props.onDownload && downloadButton));
};
return (React.createElement(Modal, { includeDefaultStyles: false, getApplicationNode: function () { return document.querySelector("#".concat(applicationId)); }, onExit: this.handleClose, focusDialog: true, titleId: "md-lightbox", dialogClass: "md-lightbox", underlayClass: "md-lightbox__container", "aria-labelledby": this.nameId },
React.createElement(MomentumThemeProvider, { theme: this.props.theme },
React.createElement("div", { className: "md-lightbox__header" },
React.createElement("div", { className: "md-lightbox__header-item--left" },
React.createElement("div", { className: "md-lightbox__header-meta" },
React.createElement("div", { className: "md-lightbox__header-sharer" }, info.sharedBy),
React.createElement("div", { className: "md-lightbox__header-timestamp" }, info.sharedOn))),
React.createElement("div", { className: "md-lightbox__header-item--center" },
React.createElement("h2", { className: "md-lightbox__header-name", id: this.nameId }, name)),
React.createElement("div", { className: "md-lightbox__header-item--right" },
React.createElement(TooltipNext, { style: LightThemeStyle, type: "label", placement: "bottom-start", triggerComponent: React.createElement(ButtonSimple, { className: "md-lightbox__control md-lightbox__control-close", onPress: this.handleClose },
React.createElement(IconNext, { name: "cancel", fillColor: "var(--mds-color-theme-common-text-primary-normal)", scale: 20, weight: "light" })) }, tooltips.exit))),
React.createElement("div", { className: "md-lightbox__body", ref: function (ref) { return (_this.lightBox = ref); }, role: "tablist" },
showColumn && getThumbnails(),
React.createElement("div", { className: "md-lightbox__content" },
React.createElement("div", { className: "md-lightbox__viewport" +
"".concat((!!currentPage.decrypting && " md-lightbox__viewport--decrypting") || ''), ref: function (ref) { return (_this.viewport = ref); } },
pages[index].decrypting && (React.createElement(LoadingSpinner, { className: "md-lightbox__decrypting-spinner", "aria-hidden": true, scale: 32 })),
getViewport()),
showColumn && leftArrowControl,
showColumn && rightArrowControl,
viewportControls())))));
};
return Lightbox;
}(React.Component));
Lightbox.propTypes = {
/** @prop ID for Lightbox query lookup */
applicationId: PropTypes.string.isRequired,
/** Determines if info is decrypting | false */
decrypting: PropTypes.bool,
/** @prop Optional downloading css styling | false */
downloading: PropTypes.bool,
/** @prop Set Height value of Lightbox */
height: PropTypes.number.isRequired,
/** @prop Classname appended to img viewport | '' */
imgClassName: PropTypes.string,
/** @prop Initial index of start page | 0 */
index: PropTypes.number,
/** @prop Lightbox information Object | {} */
info: PropTypes.shape({
sharedBy: PropTypes.string,
sharedOn: PropTypes.string,
size: PropTypes.string,
}),
/** @prop Optional indication if image is rotated | false */
isImageRotated: PropTypes.bool,
/** @prop Required name prop for Lightbox */
name: PropTypes.string.isRequired,
/** @prop Callback function invoked by user when interact with Lightbox | null */
onChange: PropTypes.func,
/** @prop Callback function invoked by user closing the Lightbox | null */
onClose: PropTypes.func,
/** @prop Callback function invoked by the download action of Lightbox | null */
onDownload: PropTypes.func,
/** @prop Array of Lightbox pages */
pages: PropTypes.array.isRequired,
/** @prop tooltip style | {isContained:true, direction: 'bottom-right'} */
popoverProps: PropTypes.object,
/** @prop theme -- used to pass down to the ThemeProvider */
theme: PropTypes.string,
/** @prop Collection of predefined tootips for various Lightbox actions | { download: 'Download', etc } */
tooltips: PropTypes.shape({
download: PropTypes.string,
downloading: PropTypes.string,
exit: PropTypes.string,
previous: PropTypes.string,
next: PropTypes.string,
zoomIn: PropTypes.string,
zoomOut: PropTypes.string,
}),
/** @prop Set Width value for Lightbox */
width: PropTypes.number.isRequired,
};
Lightbox.defaultProps = {
decrypting: false,
downloading: false,
imgClassName: '',
index: 0,
info: {},
isImageRotated: false,
name: '',
onChange: null,
onClose: null,
onDownload: null,
popoverProps: {
isContained: true,
direction: 'bottom-right',
},
theme: 'darkWebex',
tooltips: {
download: 'Download',
downloading: 'Downloading...',
exit: 'Exit',
previous: 'Previous',
next: 'Next',
zoomIn: 'Zoom in',
zoomOut: 'Zoom out',
},
};
Lightbox.displayName = 'Lightbox';
export default Lightbox;
//# sourceMappingURL=index.js.map