UNPKG

quiz-interactions

Version:

A React UI component Library for quiz interaction types.

474 lines (412 loc) 19 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf3 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _react = _interopRequireWildcard(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _reactDom = _interopRequireDefault(require("react-dom")); var _debounce = _interopRequireDefault(require("lodash/debounce")); var _uiButtons = require("@instructure/ui-buttons"); var _uiIcons = require("@instructure/ui-icons"); var _uiForms = require("@instructure/ui-forms"); var _uiElements = require("@instructure/ui-elements"); var _uiA11y = require("@instructure/ui-a11y"); var _uiOverlays = require("@instructure/ui-overlays"); var _uiThemeable = require("@instructure/ui-themeable"); var _quizCommon = require("@instructure/quiz-common"); var _Errors = _interopRequireDefault(require("../../../common/edit/components/Errors")); var _theme = _interopRequireDefault(require("./theme")); var _formatMessage = _interopRequireDefault(require("@instructure/quiz-i18n/lib/format-message")); var _dec, _class, _class2, _temp; var styles = { componentId: 'cKODt', template: function template(theme) { return "\n\n.cKODt_vGMs{border:".concat(theme.mainContainerBorderWidth || 'inherit', " solid ").concat(theme.mainContainerBorderColor || 'inherit', ";display:flex;flex-direction:column;margin-top:").concat(theme.mainContainerMargin || 'inherit', ";width:100%}\n\n.cKODt_dfjU{align-items:center;display:flex;padding:").concat(theme.mainContainerHeaderPadding || 'inherit', "}\n\n.cKODt_bVGR{display:flex;padding-left:").concat(theme.mainContainerTypePadding || 'inherit', "}\n\n.cKODt_Ader{background-color:").concat(theme.mainContainerTypeUnselectedColor || 'inherit', "}\n\n.cKODt_dATc{background-color:").concat(theme.mainContainerTypeSelectedColor || 'inherit', ";box-shadow:2px 2px 3px ").concat(theme.mainContainerTypeSelectedShadowColor || 'inherit', "}\n\n.cKODt_cdWv{padding:").concat(theme.popoverContentPadding || 'inherit', "}\n\n.cKODt_fUbv{border-left:").concat(theme.mainContainerActionsBorderWidth || 'inherit', " solid ").concat(theme.mainContainerActionsBorderColor || 'inherit', ";display:flex;flex:1;margin-left:").concat(theme.mainContainerActionsMargin || 'inherit', ";padding-left:").concat(theme.mainContainerActionsPadding || 'inherit', "}\n\n.cKODt_fFFh{display:flex;flex:1;justify-content:flex-end}\n\n.cKODt_fAhB{align-items:baseline;display:flex}\n\n.cKODt_eVMz{align-items:center;background-color:").concat(theme.mainContainerContentWrapperBackgroundColor || 'inherit', ";display:flex;justify-content:center;padding:").concat(theme.mainContainerContentWrapperPadding || 'inherit', ";position:relative}\n\n.cKODt_edLH{max-height:70vh;max-width:100%}\n\n.cKODt_jcDT{max-width:calc(100% - 0.01px);position:relative}\n\n.cKODt_ciua{margin-top:").concat(theme.fileDropWrapperMargin || 'inherit', "}\n\n.cKODt_DxCw{align-items:center;background-color:").concat(theme.fileDropContentBackgroundColor || 'inherit', ";display:flex;justify-content:center;padding:").concat(theme.fileDropContentPadding || 'inherit', " 0}\n\n.cKODt_eeJQ{display:flex;font-size:").concat(theme.fileDropContentIconFontSize || 'inherit', "}\n\n.cKODt_cmNy{display:flex;font-family:").concat(theme.fileDropContentLabelFontFamily || 'inherit', ";padding-left:").concat(theme.fileDropContentLabelPadding || 'inherit', "}\n\n.cKODt_eItU{color:").concat(theme.fileDropContentLabelBrowseColor || 'inherit', ";padding-left:").concat(theme.fileDropContentLabelBrowsePadding || 'inherit', ";text-decoration:underline}\n\n.cKODt_dlsh{display:flex;flex:1;flex-direction:column}\n\n.cKODt_esoK{background-color:").concat(theme.modalContentTypesBackgroundColor || 'inherit', ";padding:").concat(theme.modalContentTypesPadding || 'inherit', "}\n\n.cKODt_GdGA{align-items:center;background-color:").concat(theme.modalContentImageBackgroundColor || 'inherit', ";display:flex;justify-content:center;position:relative}\n\n.cKODt_Xtpo{background:rgba(0,0,0,0.5);height:100%;width:100%}\n\n.cKODt_badM,.cKODt_Xtpo{left:50%;position:absolute;top:50%;transform:translate(-50%,-50%)}"); }, 'mainContainer': 'cKODt_vGMs', 'mainContainerHeader': 'cKODt_dfjU', 'mainContainerType': 'cKODt_bVGR', 'mainContainerTypeUnselected': 'cKODt_Ader', 'mainContainerTypeSelected': 'cKODt_dATc', 'popoverContent': 'cKODt_cdWv', 'mainContainerActions': 'cKODt_fUbv', 'mainContainerActionsRemove': 'cKODt_fFFh', 'headerText': 'cKODt_fAhB', 'mainContainerContentWrapper': 'cKODt_eVMz', 'mainContainerContentImage': 'cKODt_edLH', 'imageHolder': 'cKODt_jcDT', 'fileDropWrapper': 'cKODt_ciua', 'fileDropContent': 'cKODt_DxCw', 'fileDropContentIcon': 'cKODt_eeJQ', 'fileDropContentLabel': 'cKODt_cmNy', 'fileDropContentLabelBrowse': 'cKODt_eItU', 'modalContent': 'cKODt_dlsh', 'modalContentTypes': 'cKODt_esoK', 'modalContentImage': 'cKODt_GdGA', 'spinnerWrapper': 'cKODt_Xtpo', 'spinner': 'cKODt_badM' }; var _ref3 = /*#__PURE__*/ _react.default.createElement(_uiIcons.IconUploadLine, null); var DrawingContainer = (_dec = (0, _uiThemeable.themeable)(_theme.default, styles), _dec(_class = (_temp = _class2 = /*#__PURE__*/ function (_Component) { (0, _inherits2.default)(DrawingContainer, _Component); function DrawingContainer() { var _getPrototypeOf2; var _this; (0, _classCallCheck2.default)(this, DrawingContainer); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = (0, _possibleConstructorReturn2.default)(this, (_getPrototypeOf2 = (0, _getPrototypeOf3.default)(DrawingContainer)).call.apply(_getPrototypeOf2, [this].concat(args))); _this.state = { imageWidth: 0, imageHeight: 0, isModalOpen: false }; _this.currentCoordinates = function () { var currentCoordinates = _this.props.coordinates.map(function (item) { var x = item.x * _this.state.imageWidth; var y = item.y * _this.state.imageHeight; return { x: x, y: y }; }); return currentCoordinates; }; _this.currentImageWidth = function () { return _this.state.imageWidth; }; _this.currentImageHeight = function () { return _this.state.imageHeight; }; _this.updateSize = (0, _debounce.default)(function () { if (_this.props.url && _this.image) { // ref element (this.image) is not enough to get the updated image dimensions var rectObject = _reactDom.default.findDOMNode(_this.image).getBoundingClientRect(); _this.setDimensions(rectObject); } }, 50); _this.setDimensions = function (rectObject) { _this.setState({ imageWidth: rectObject.width, imageHeight: rectObject.height }); }; _this.handleImageLoad = function (e) { _this.setDimensions({ height: e.target.offsetHeight, width: e.target.offsetWidth }); }; _this.handleSelectDrawOption = function (type) { _this.canvas.clearCanvas(); _this.props.onSetType(type); }; _this.handleExpandImage = function () { _this.props.onModalOpen(); _this.setState({ isModalOpen: true }); }; _this.handleCloseModal = function () { _this.props.onModalClose(); _this.setState({ isModalOpen: false }); }; _this.handleCanvasRef = function (node) { _this.canvas = node && node.canvas; }; _this.handleImageRef = function (node) { _this.image = node; }; _this.handleFileDropRef = function (node) { _this.fileDrop = node; }; return _this; } (0, _createClass2.default)(DrawingContainer, [{ key: "componentDidMount", value: function componentDidMount() { window.addEventListener('resize', this.updateSize); this.updateSize(); } }, { key: "componentDidUpdate", value: function componentDidUpdate(lastProps) { if (lastProps.url && this.props.url === void 0) { this.fileDrop.fileInputEl.focus(); } this.updateSize(); } }, { key: "componentWillUnmount", value: function componentWillUnmount() { window.removeEventListener('resize', this.updateSize); this.updateSize.cancel(); } // =========== // HELPERS // =========== }, { key: "getSelectedTypeComponent", value: function getSelectedTypeComponent() { var _this2 = this; var type = this.props.drawTypes.find(function (item) { return item.type === _this2.props.currentType; }); return type.component; } }, { key: "renderCanvas", // =========== // RENDER // =========== value: function renderCanvas() { if (!this.props.currentType || this.props.isUploading) { return null; } var SelectedType = this.getSelectedTypeComponent(); return _react.default.createElement(SelectedType, { ref: this.handleCanvasRef, handleSetCoordinates: this.props.convertCoordinates, coordinates: this.currentCoordinates(), width: this.state.imageWidth, height: this.state.imageHeight }); } }, { key: "renderTypes", value: function renderTypes() { var _this3 = this; return _react.default.createElement("div", { className: styles.mainContainerType }, this.props.drawTypes.map(function (item) { var TypeIcon = item.icon; var onButtonClick = function onButtonClick() { return _this3.handleSelectDrawOption(item.type); }; var variant = 'icon'; var wrapperClassName = styles.mainContainerTypeUnselected; if (item.type === _this3.props.currentType) { onButtonClick = null; variant = 'icon-inverse'; wrapperClassName = styles.mainContainerTypeSelected; } return _react.default.createElement(_uiOverlays.Popover, { key: item.type, variant: "inverse", onClick: onButtonClick }, _react.default.createElement(_uiOverlays.Popover.Trigger, null, _react.default.createElement("div", { className: wrapperClassName }, _react.default.createElement(_uiButtons.Button, { variant: variant }, _react.default.createElement(TypeIcon, { title: item.title })))), _react.default.createElement(_uiOverlays.Popover.Content, null, _react.default.createElement("div", { className: styles.popoverContent }, item.title))); })); } }, { key: "renderActionButton", value: function renderActionButton(onClick, label, Icon) { return _react.default.createElement(_uiOverlays.Popover, { onClick: onClick, variant: "inverse" }, _react.default.createElement(_uiOverlays.Popover.Trigger, null, _react.default.createElement(_uiButtons.Button, { variant: "icon", icon: Icon }, _react.default.createElement(_uiA11y.ScreenReaderContent, null, label))), _react.default.createElement(_uiOverlays.Popover.Content, null, _react.default.createElement("div", { className: styles.popoverContent }, label))); } }, { key: "renderActions", value: function renderActions() { return _react.default.createElement("div", { className: styles.mainContainerActions }, this.renderActionButton(this.handleExpandImage, (0, _formatMessage.default)('Expand Image'), _uiIcons.IconExpandItemsLine), _react.default.createElement("div", { className: styles.mainContainerActionsRemove }, this.renderActionButton(this.props.onRemoveImage, (0, _formatMessage.default)('Remove Image'), _uiIcons.IconTrashLine))); } }, { key: "renderHeaderText", value: function renderHeaderText(isModal) { var _this4 = this; if (this.props.currentType === 'polygon' && this.props.coordinates.length > 0) { return _react.default.createElement("div", { className: styles.headerText }, _formatMessage.default.rich('<0>Double click to</0> <1>close shape</1>', [function (_ref) { var children = _ref.children; return _react.default.createElement(_uiElements.Text, { key: "1" }, children); }, function (_ref2) { var children = _ref2.children; return _react.default.createElement(_uiButtons.Button, { key: "2", variant: "link", as: "a", size: "large", theme: { largePadding: _this4.theme.polygonButtonPadding, largeFontSize: isModal ? _this4.theme.polygonButtonFontSize : null, largeHeight: '0' } }, children); }])); } return _react.default.createElement(_uiElements.Text, { color: "primary" }, (0, _formatMessage.default)('Draw the hot spot\'s shape')); } }, { key: "renderImage", value: function renderImage() { return _react.default.createElement("div", { className: styles.imageHolder }, _react.default.createElement("img", { alt: (0, _formatMessage.default)('Uploaded Image'), className: styles.mainContainerContentImage, onLoad: this.handleImageLoad, ref: this.handleImageRef, src: this.props.url }), !this.props.isUploading ? null : _react.default.createElement("div", { className: styles.spinnerWrapper }, _react.default.createElement("div", { className: styles.spinner }, _react.default.createElement(_uiElements.Spinner, { renderTitle: (0, _formatMessage.default)('Loading'), size: "large", variant: "inverse" }))), this.renderCanvas()); } }, { key: "renderDrawingContainer", value: function renderDrawingContainer() { return _react.default.createElement("div", { className: styles.mainContainer }, this.props.isUploading ? null : _react.default.createElement("div", { className: styles.mainContainerHeader }, _react.default.createElement(_Errors.default, { errorList: this.props.typeErrors, errorsFirst: false }, _react.default.createElement("div", { className: styles.mainContainerHeader }, _react.default.createElement("div", null, this.renderHeaderText()), this.renderTypes())), this.renderActions()), _react.default.createElement("div", { className: styles.mainContainerContentWrapper }, this.renderImage())); } }, { key: "renderFileDropContent", value: function renderFileDropContent() { return _react.default.createElement("div", { className: styles.fileDropContent }, _react.default.createElement("div", { className: styles.fileDropContentIcon }, _ref3), _react.default.createElement("div", { className: styles.fileDropContentLabel }, _formatMessage.default.rich("Drag n' Drop here or <0>Browse</0>", [function (_ref4) { var children = _ref4.children; return _react.default.createElement("div", { key: "1", className: styles.fileDropContentLabelBrowse }, children); }]))); } }, { key: "renderFileDrop", value: function renderFileDrop() { return _react.default.createElement(_Errors.default, { errorList: this.props.fileDropErrors }, _react.default.createElement("div", { className: styles.fileDropWrapper }, _react.default.createElement(_uiForms.FileDrop, { accept: "image/*", label: this.renderFileDropContent(), onDropAccepted: this.props.onDropAccepted, ref: this.handleFileDropRef }))); } }, { key: "renderModal", value: function renderModal() { return _react.default.createElement(_quizCommon.SimpleModal, { footerContent: _react.default.createElement(_uiButtons.Button, { onClick: this.handleCloseModal, variant: "primary" }, (0, _formatMessage.default)('Done')), isModalOpen: this.state.isModalOpen, onModalDismiss: this.handleCloseModal, size: "fullscreen", title: this.renderHeaderText(true), label: (0, _formatMessage.default)('Modal Dialog: Draw a hot spot') }, _react.default.createElement("div", { className: styles.modalContent }, _react.default.createElement("div", { className: styles.modalContentTypes }, this.renderTypes()), _react.default.createElement("div", { className: styles.modalContentImage }, this.renderImage()))); } }, { key: "render", value: function render() { if (!this.props.url) { return _react.default.createElement("div", null, this.renderFileDrop()); } else if (this.state.isModalOpen === true) { return _react.default.createElement("div", null, this.renderModal()); } else { return _react.default.createElement("div", null, this.renderDrawingContainer(), _react.default.createElement(_Errors.default, { errorList: this.props.canvasErrors, showBorder: false })); } } }]); DrawingContainer.displayName = "DrawingContainer"; return DrawingContainer; }(_react.Component), _class2.propTypes = { canvasErrors: _propTypes.default.array, coordinates: _propTypes.default.array, convertCoordinates: _propTypes.default.func, currentType: _propTypes.default.string, drawTypes: _propTypes.default.array, fileDropErrors: _propTypes.default.array, isUploading: _propTypes.default.bool, onModalOpen: _propTypes.default.func, onModalClose: _propTypes.default.func, onDropAccepted: _propTypes.default.func, onSetType: _propTypes.default.func, onRemoveImage: _propTypes.default.func, typeErrors: _propTypes.default.array, url: _propTypes.default.string }, _class2.defaultProps = { onModalOpen: Function.prototype, onModalClose: Function.prototype, canvasErrors: void 0, coordinates: void 0, convertCoordinates: void 0, currentType: void 0, drawTypes: void 0, fileDropErrors: void 0, isUploading: void 0, onDropAccepted: void 0, onSetType: void 0, onRemoveImage: void 0, typeErrors: void 0, url: void 0 }, _temp)) || _class); exports.default = DrawingContainer;