quiz-interactions
Version:
A React UI component Library for quiz interaction types.
474 lines (412 loc) • 19 kB
JavaScript
"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;