@instructure/quiz-interactions
Version:
A React UI component Library for quiz interaction types.
374 lines (368 loc) • 17.1 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
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 _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireWildcard(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _isEmpty = _interopRequireDefault(require("lodash/fp/isEmpty"));
var _quizRce = require("@instructure/quiz-rce");
var _uiText = require("@instructure/ui-text");
var _uiButtons = require("@instructure/ui-buttons");
var _quizCommon = require("@instructure/quiz-common");
var _uiIcons = require("@instructure/ui-icons");
var _uiModal = require("@instructure/ui-modal");
var _uiHeading = require("@instructure/ui-heading");
var _uiTable = require("@instructure/ui-table");
var _TargetContainer = _interopRequireDefault(require("../common/TargetContainer"));
var _formatMessage = _interopRequireDefault(require("@instructure/quiz-i18n/es/format-message"));
var _Target = _interopRequireDefault(require("./Target"));
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _callSuper(_this, derived, args) {
function isNativeReflectConstruct() {
if (typeof Reflect === "undefined" || !Reflect.construct) return false;
if (Reflect.construct.sham) return false;
if (typeof Proxy === "function") return true;
try {
return !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
} catch (e) {
return false;
}
}
derived = (0, _getPrototypeOf2["default"])(derived);
return (0, _possibleConstructorReturn2["default"])(_this, isNativeReflectConstruct() ? Reflect.construct(derived, args || [], (0, _getPrototypeOf2["default"])(_this).constructor) : derived.apply(_this, args));
}
/**
---
category: HotSpot
---
HotSpot Take component
```jsx_example
function Example (props) {
const exampleProps = {
itemBody: 'Which of these players is David Ferrer',
interactionData: {
imageUrl: 'https://i.ytimg.com/vi/LgkAebhJ7iE/maxresdefault.jpg'
},
userResponse: {
value: {
x: 0.3,
y: 0.3
}
}
}
return (
<HotSpotTake {...exampleProps} {...props} />
)
}
<SettingsSwitcher locales={LOCALES}>
<TakeStateProvider>
<Example />
</TakeStateProvider>
</SettingsSwitcher>
```
**/
var HotSpotTake = exports["default"] = /*#__PURE__*/function (_Component) {
function HotSpotTake(props) {
var _this2;
(0, _classCallCheck2["default"])(this, HotSpotTake);
_this2 = _callSuper(this, HotSpotTake, [props]);
(0, _defineProperty2["default"])(_this2, "canAddPoint", function () {
var _this2$state = _this2.state,
selectedCoordinates = _this2$state.selectedCoordinates,
keyboardCoordinates = _this2$state.keyboardCoordinates;
var hotspotsCount = _this2.props.interactionData.hotspotsCount;
var totalSelections = selectedCoordinates.length + (keyboardCoordinates ? 1 : 0);
return totalSelections < (hotspotsCount || 1);
});
(0, _defineProperty2["default"])(_this2, "saveSelectedPoint", function () {
var _this2$state2 = _this2.state,
selectedCoordinates = _this2$state2.selectedCoordinates,
keyboardCoordinates = _this2$state2.keyboardCoordinates;
var _this2$props = _this2.props,
multipleHotSpotEnabled = _this2$props.multipleHotSpotEnabled,
hotspotsCount = _this2$props.interactionData.hotspotsCount;
if (!keyboardCoordinates) return;
var updatedCoordinates = [].concat((0, _toConsumableArray2["default"])(selectedCoordinates), [keyboardCoordinates]);
_this2.setState({
selectedCoordinates: updatedCoordinates,
keyboardCoordinates: null,
isSelectingPoint: false
});
var response = !multipleHotSpotEnabled && (!hotspotsCount || hotspotsCount === 1) ? keyboardCoordinates : updatedCoordinates;
_this2.props.handleResponseUpdate(response);
});
(0, _defineProperty2["default"])(_this2, "handleKeyDown", function (event) {
var stepSize = 0.05;
var key = event.key;
if (!_this2.state.focusedContainer) return;
if (_this2.isAnyInputFocused()) return;
if (key === 's') {
_this2.startSelectingPoint();
} else if (key === 'd' && _this2.state.isSelectingPoint) {
_this2.saveSelectedPoint();
} else if (key === 'Backspace' || key === 'Delete') {
_this2.handleResetSelections();
} else if (_this2.isArrowKey(key) && _this2.state.keyboardCoordinates) {
event.preventDefault();
_this2.movePosition(key, stepSize);
}
});
(0, _defineProperty2["default"])(_this2, "startSelectingPoint", function () {
if (!_this2.canAddPoint()) return;
_this2.setState({
keyboardCoordinates: {
x: 0.5,
y: 0.5
},
isSelectingPoint: true
});
});
(0, _defineProperty2["default"])(_this2, "isArrowKey", function (key) {
return ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(key);
});
(0, _defineProperty2["default"])(_this2, "movePosition", function (key, stepSize) {
var _this2$state$keyboard = _this2.state.keyboardCoordinates,
x = _this2$state$keyboard.x,
y = _this2$state$keyboard.y;
var offsets = {
ArrowUp: {
x: x,
y: Math.max(y - stepSize, 0)
},
ArrowDown: {
x: x,
y: Math.min(y + stepSize, 1)
},
ArrowLeft: {
x: Math.max(x - stepSize, 0),
y: y
},
ArrowRight: {
x: Math.min(x + stepSize, 1),
y: y
}
};
_this2.setState({
keyboardCoordinates: offsets[key]
});
});
(0, _defineProperty2["default"])(_this2, "handleSetCoordinates", function (coordinatesArray) {
if (!_this2.canAddPoint()) return;
var selectedCoordinates = _this2.state.selectedCoordinates;
var _this2$props2 = _this2.props,
multipleHotSpotEnabled = _this2$props2.multipleHotSpotEnabled,
hotspotsCount = _this2$props2.interactionData.hotspotsCount;
var x = coordinatesArray[0].x / _this2.targetContainer.state.imageWidth;
var y = coordinatesArray[0].y / _this2.targetContainer.state.imageHeight;
var updatedCoordinates = [].concat((0, _toConsumableArray2["default"])(selectedCoordinates), [{
x: x,
y: y
}]);
_this2.setState({
selectedCoordinates: updatedCoordinates
});
var response = !multipleHotSpotEnabled && (!hotspotsCount || hotspotsCount === 1) ? {
x: x,
y: y
} : updatedCoordinates;
_this2.props.handleResponseUpdate(response);
});
(0, _defineProperty2["default"])(_this2, "targetContainerRef", function (node) {
_this2.targetContainer = node;
});
(0, _defineProperty2["default"])(_this2, "handleResetSelections", function () {
_this2.setState({
selectedCoordinates: [],
keyboardCoordinates: null
});
_this2.props.handleResponseUpdate([]);
});
(0, _defineProperty2["default"])(_this2, "handleCloseShortcutsClick", function () {
_this2.setState({
shortcutsModalOpen: false
});
});
(0, _defineProperty2["default"])(_this2, "handleOpenShortcutsClick", function () {
_this2.setState({
shortcutsModalOpen: true
});
});
_this2.state = {
selectedCoordinates: [],
keyboardCoordinates: null,
isSelectingPoint: false,
focusedContainer: null,
shortcutsModalOpen: false
};
return _this2;
}
(0, _inherits2["default"])(HotSpotTake, _Component);
return (0, _createClass2["default"])(HotSpotTake, [{
key: "componentDidMount",
value: function componentDidMount() {
var _this$props$userRespo;
window.addEventListener('keydown', this.handleKeyDown);
var value = (_this$props$userRespo = this.props.userResponse) === null || _this$props$userRespo === void 0 ? void 0 : _this$props$userRespo.value;
if (!(0, _isEmpty["default"])(value)) {
this.setState({
selectedCoordinates: Array.isArray(value) ? value : [value]
});
}
}
}, {
key: "componentWillUnmount",
value: function componentWillUnmount() {
window.removeEventListener('keydown', this.handleKeyDown);
}
}, {
key: "isAnyInputFocused",
value: function isAnyInputFocused() {
var inputs = document.querySelectorAll('input');
return Array.from(inputs).some(function (input) {
return input === document.activeElement;
});
}
}, {
key: "render",
value:
// ===========
// RENDER
// ===========
function render() {
var _this3 = this;
var _this$state = this.state,
selectedCoordinates = _this$state.selectedCoordinates,
keyboardCoordinates = _this$state.keyboardCoordinates;
var hotspots = selectedCoordinates.length > 0 || keyboardCoordinates ? [].concat((0, _toConsumableArray2["default"])(selectedCoordinates.map(function (coordinate) {
return {
coordinates: [coordinate],
drawingType: _Target["default"]
};
})), (0, _toConsumableArray2["default"])(keyboardCoordinates ? [{
coordinates: [keyboardCoordinates],
drawingType: _Target["default"]
}] : [])) : [{
coordinates: [{}],
drawingType: _Target["default"]
}];
var keyboardShortcuts = [{
id: 'select',
shortcut: 'S',
action: (0, _formatMessage["default"])('Select a point')
}, {
id: 'save',
shortcut: 'D',
action: (0, _formatMessage["default"])('Save the position')
}, {
id: 'delete',
shortcut: 'Backspace/Delete',
action: (0, _formatMessage["default"])('Clear all selections')
}, {
id: 'move',
shortcut: 'Arrow keys',
action: (0, _formatMessage["default"])('Move the point')
}];
return /*#__PURE__*/_react["default"].createElement(_quizRce.ItemBodyWrapper, {
itemBody: this.props.itemBody
}, /*#__PURE__*/_react["default"].createElement("div", {
className: "fs-mask"
}, /*#__PURE__*/_react["default"].createElement(_TargetContainer["default"], {
hotspots: hotspots,
handleSetCoordinates: this.handleSetCoordinates,
ref: this.targetContainerRef,
url: this.props.interactionData.imageUrl,
onFocus: function onFocus() {
return _this3.setState({
focusedContainer: _this3.targetContainer
});
},
onBlur: function onBlur() {
return _this3.setState({
focusedContainer: null
});
}
})), /*#__PURE__*/_react["default"].createElement(_quizCommon.Flex, {
direction: "row",
justifyItems: "space-between",
alignItems: "center",
gap: "small",
margin: "x-small 0 0"
}, /*#__PURE__*/_react["default"].createElement(_quizCommon.Flex.Item, null, this.state.selectedCoordinates.length > 0 && /*#__PURE__*/_react["default"].createElement(_uiButtons.CondensedButton, {
onClick: this.handleResetSelections,
"data-automation": "sdk-hotspot-take-clear-selections-button"
}, (0, _formatMessage["default"])('Clear my selection'))), /*#__PURE__*/_react["default"].createElement(_quizCommon.Flex.Item, null, /*#__PURE__*/_react["default"].createElement(_uiButtons.IconButton, {
color: "secondary",
screenReaderLabel: (0, _formatMessage["default"])('Show keyboard shortcuts'),
withBackground: false,
withBorder: false,
onClick: this.handleOpenShortcutsClick
}, /*#__PURE__*/_react["default"].createElement(_uiIcons.IconKeyboardShortcutsLine, null)), /*#__PURE__*/_react["default"].createElement(_uiModal.Modal, {
size: "medium",
label: (0, _formatMessage["default"])('Keyboard shortcuts'),
open: this.state.shortcutsModalOpen,
onDismiss: this.handleCloseShortcutsClick,
shouldCloseOnDocumentClick: true
}, /*#__PURE__*/_react["default"].createElement(_uiModal.Modal.Header, null, /*#__PURE__*/_react["default"].createElement(_uiHeading.Heading, {
level: "h2"
}, (0, _formatMessage["default"])('Keyboard shortcuts')), /*#__PURE__*/_react["default"].createElement(_uiButtons.CloseButton, {
placement: "end",
offset: "small",
onClick: this.handleCloseShortcutsClick,
screenReaderLabel: (0, _formatMessage["default"])('Close')
})), /*#__PURE__*/_react["default"].createElement(_uiModal.Modal.Body, null, /*#__PURE__*/_react["default"].createElement(_uiTable.Table, {
caption: (0, _formatMessage["default"])('Keyboard shortcuts')
}, /*#__PURE__*/_react["default"].createElement(_uiTable.Table.Head, null, /*#__PURE__*/_react["default"].createElement(_uiTable.Table.Row, null, /*#__PURE__*/_react["default"].createElement(_uiTable.Table.ColHeader, {
id: "shortcut"
}, (0, _formatMessage["default"])('Shortcut')), /*#__PURE__*/_react["default"].createElement(_uiTable.Table.ColHeader, {
id: "action"
}, (0, _formatMessage["default"])('Action')))), /*#__PURE__*/_react["default"].createElement(_uiTable.Table.Body, null, keyboardShortcuts.map(function (_ref) {
var id = _ref.id,
shortcut = _ref.shortcut,
action = _ref.action;
return /*#__PURE__*/_react["default"].createElement(_uiTable.Table.Row, {
key: id
}, /*#__PURE__*/_react["default"].createElement(_uiTable.Table.RowHeader, null, /*#__PURE__*/_react["default"].createElement(_uiText.Text, {
id: "shortcut-".concat(id)
}, shortcut)), /*#__PURE__*/_react["default"].createElement(_uiTable.Table.Cell, null, /*#__PURE__*/_react["default"].createElement(_uiText.Text, {
id: "action-".concat(id)
}, action)));
})))), /*#__PURE__*/_react["default"].createElement(_uiModal.Modal.Footer, null, /*#__PURE__*/_react["default"].createElement(_uiButtons.Button, {
onClick: this.handleCloseShortcutsClick
}, (0, _formatMessage["default"])('Close')))))));
}
}]);
}(_react.Component);
(0, _defineProperty2["default"])(HotSpotTake, "propTypes", {
handleResponseUpdate: _propTypes["default"].func.isRequired,
interactionData: _propTypes["default"].shape({
imageUrl: _propTypes["default"].string.isRequired,
hotspotsCount: _propTypes["default"].number
}).isRequired,
itemBody: _propTypes["default"].string.isRequired,
userResponse: _propTypes["default"].shape({
value: _propTypes["default"].oneOfType([_propTypes["default"].arrayOf(_propTypes["default"].shape({
x: _propTypes["default"].number,
y: _propTypes["default"].number
})), _propTypes["default"].shape({
x: _propTypes["default"].number,
y: _propTypes["default"].number
})]).isRequired
}),
scoringData: _propTypes["default"].shape({
value: _propTypes["default"].arrayOf(_propTypes["default"].shape({
x: _propTypes["default"].number,
y: _propTypes["default"].number
})).isRequired
}),
multipleHotSpotEnabled: _propTypes["default"].bool
});