UNPKG

@instructure/quiz-interactions

Version:

A React UI component Library for quiz interaction types.

291 lines (287 loc) • 12.5 kB
/** @jsx jsx */ function _array_like_to_array(arr, len) { if (len == null || len > arr.length) len = arr.length; for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i]; return arr2; } function _array_without_holes(arr) { if (Array.isArray(arr)) return _array_like_to_array(arr); } function _define_property(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _iterable_to_array(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } function _non_iterable_spread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _object_spread(target) { for(var i = 1; i < arguments.length; i++){ var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === "function") { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function(key) { _define_property(target, key, source[key]); }); } return target; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function(sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } function _object_spread_props(target, source) { source = source != null ? source : {}; if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function(key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } function _to_consumable_array(arr) { return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread(); } function _unsupported_iterable_to_array(o, minLen) { if (!o) return; if (typeof o === "string") return _array_like_to_array(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(n); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen); } import React, { useCallback, useMemo } from 'react'; import PropTypes from 'prop-types'; import { Alert } from '@instructure/ui-alerts'; import { Text } from '@instructure/ui-text'; import { jsx } from '@instructure/emotion'; import { ItemBodyWrapper } from '@instructure/quiz-rce/components/ItemBodyWrapper/index'; import t from '@instructure/quiz-i18n/format-message'; import Wordbank from '../drag_components/Wordbank'; import TakeStem from './take_components/TakeStem'; import generateStyle from './styles'; import generateComponentTheme from './theme'; import { withStyleOverrides } from '@instructure/quiz-common/util/withStyleOverrides'; /** --- category: FillInTheBlank --- Fill in the Blank Take component ```jsx_example function Example (props) { const exampleProps = { interactionData: { prompt: '<p><strong>Please</strong> fill in all the blanks</p>', stemItems: [ { id: 'stem_uuid-1', position: 1, type: 'text', value: ' ... ' }, { id: 'stem_uuid0', position: 2, type: 'blank', blankId: 'fitb_uuid1' }, { id: 'stem_uuid1', position: 3, type: 'text', value: ' Columbus sailed in ' }, { id: 'stem_uuid2', position: 4, type: 'blank', blankId: 'fitb_uuid2' }, { id: 'stem_uuid3', position: 5, type: 'text', value: ' , from the country of ' }, { id: 'stem_uuid4', position: 6, type: 'blank', blankId: 'fitb_uuid3' }, { id: 'stem_uuid5', position: 7, type: 'text', value: ' , on the continent of ' }, { id: 'stem_uuid6', position: 8, type: 'blank', blankId: 'fitb_uuid4' }, { id: 'stem_uuid7', position: 9, type: 'text', value: ' , across the ' }, { id: 'stem_uuid8', position: 10, type: 'blank', blankId: 'fitb_uuid5' }, { id: 'stem_uuid9', position: 11, type: 'text', value: ' , and found... ' }, { id: 'stem_uuid10', position: 12, type: 'blank', blankId: 'fitb_uuid6' }, { id: 'stem_uuid11', position: 13, type: 'text', value: ' !!! ' }, { id: 'stem_uuid12', position: 14, type: 'text', value: ' Where the people were " ' }, { id: 'stem_uuid13', position: 15, type: 'blank', blankId: 'fitb_uuid7' }, { id: 'stem_uuid14', position: 16, type: 'text', value: ' " ' } ], blanks: [{ id: 'fitb_uuid1', answerType: 'openEntry' }, { id: 'fitb_uuid2', answerType: 'openEntry' }, { id: 'fitb_uuid3', answerType: 'openEntry' }, { id: 'fitb_uuid4', answerType: 'openEntry' }, { id: 'fitb_uuid5', answerType: 'openEntry' }, { id: 'fitb_uuid6', choices: [ { id: 'choice_uuid11_brazil', position: 1, itemBody: 'Brazil' }, { id: 'choice_uuid12_austria', position: 2, itemBody: 'Austria' }, { id: 'choice_uuid13_america', position: 3, itemBody: 'America' } ], answerType: 'wordbank' }, { id: 'fitb_uuid7', choices: [ { id: 'choice_uuid11_peaceful', position: 1, itemBody: 'peaceful' }, { id: 'choice_uuid12_war-torn', position: 2, itemBody: 'war-torn' }, { id: 'choice_uuid13_confused', position: 3, itemBody: 'confused' } ], answerType: 'dropdown' }] }, userResponse: { value: [ { id: 'fitb_uuid1', value: 'Christopher', type: 'Text'}, { id: 'fitb_uuid2', value: '1493', type: 'Text'}, { id: 'fitb_uuid3', value: 'Span', type: 'Text'}, { id: 'fitb_uuid4', value: 'Europe', type: 'Text'}, { id: 'fitb_uuid5', value: 'Atlantic', type: 'Text'}, { id: 'fitb_uuid6', value: 'choice_uuid12_austria', type: 'Text'}, { id: 'fitb_uuid7', value: 'choice_uuid13_confused', type: 'Text'} ] } } return ( <DndProvider backend={HTML5Backend}> <FillBlankTake {...exampleProps} {...props} /> </DndProvider> ) } <SettingsSwitcher locales={LOCALES}> <TakeStateProvider> <Example /> </TakeStateProvider> </SettingsSwitcher> ``` **/ // ============================================ // Sub-components // ============================================ function DeprecationWarning() { return /*#__PURE__*/ jsx(Alert, { variant: "error" }, /*#__PURE__*/ jsx(Text, { color: "primary" }, /*#__PURE__*/ jsx("b", null, t('This question type is deprecated'))), /*#__PURE__*/ jsx("ul", null, /*#__PURE__*/ jsx("li", null, t('Quizzes containing deprecated question types will fail to copy.')), /*#__PURE__*/ jsx("li", null, t('This question was unable to be automatically upgraded due to malformed data.')), /*#__PURE__*/ jsx("li", null, t('Please delete this question and recreate it using the current Fill in the Blank question type.')))); } function WordbankSection(param) { var blanks = param.blanks, response = param.response, returnChoiceToWordbank = param.returnChoiceToWordbank, wordBankChoices = param.wordBankChoices; if (blanks.find(function(blank) { return [ 'wordbank', 'dropdown' ].includes(blank.answerType); })) { return /*#__PURE__*/ jsx(Wordbank, { blanks: blanks, response: response, returnChoiceToWordbank: returnChoiceToWordbank, wordBankChoices: wordBankChoices }); } return null; } // ============================================ // Main Component // ============================================ var FillBlankTake = /*#__PURE__*/ React.forwardRef(function(props, ref) { var handleResponseUpdate = props.handleResponseUpdate, interactionData = props.interactionData, userResponse = props.userResponse, _props_readOnly = props.readOnly, readOnly = _props_readOnly === void 0 ? false : _props_readOnly, styles = props.styles; var blanks = useMemo(function() { return (interactionData === null || interactionData === void 0 ? void 0 : interactionData.blanks) || []; }, [ interactionData === null || interactionData === void 0 ? void 0 : interactionData.blanks ]); var moveChoiceToWordbank = useCallback(function(blankId, choiceId) { var responses = userResponse.value; var blank = responses.find(function(r) { return r.id === blankId; }); // Removes the answer for blank only if choice is selected response for blank if ((blank === null || blank === void 0 ? void 0 : blank.value) === choiceId) { var blankIndex = userResponse.value.findIndex(function(r) { return r.id === blankId; }); var newResponses = responses.map(function(r, i) { return i === blankIndex ? _object_spread_props(_object_spread({}, r), { value: null }) : r; }); handleResponseUpdate(newResponses); } }, [ userResponse.value, handleResponseUpdate ]); var remainingWordBankChoices = useMemo(function() { var // filter the choices which are already used _userResponse_value; var wordbankBlanks = interactionData.blanks.filter(function(blank) { return blank.answerType === 'wordbank'; }); var choices = _to_consumable_array(wordbankBlanks.map(function(blank) { return blank.choices; }).flat()); userResponse === null || userResponse === void 0 ? void 0 : (_userResponse_value = userResponse.value) === null || _userResponse_value === void 0 ? void 0 : _userResponse_value.forEach(function(response) { var choiceIndex = choices.findIndex(function(choice) { return choice.id === response.value; }); if (choiceIndex > -1) { choices.splice(choiceIndex, 1); } }); return choices; }, [ interactionData.blanks, userResponse.value ]); return /*#__PURE__*/ jsx(ItemBodyWrapper, { itemBody: interactionData.prompt }, readOnly && /*#__PURE__*/ jsx(DeprecationWarning, null), /*#__PURE__*/ jsx("div", { css: styles.question }, /*#__PURE__*/ jsx("div", { css: styles.headerSection }, /*#__PURE__*/ jsx(TakeStem, { onUpdate: handleResponseUpdate, interactionData: interactionData, returnChoiceToWordbank: moveChoiceToWordbank, userResponses: userResponse.value, readOnly: readOnly, wordBankChoices: remainingWordBankChoices })), /*#__PURE__*/ jsx(WordbankSection, { blanks: blanks, response: userResponse.value, returnChoiceToWordbank: moveChoiceToWordbank, wordBankChoices: remainingWordBankChoices }))); }); FillBlankTake.displayName = 'FillBlankTake'; FillBlankTake.propTypes = { handleResponseUpdate: PropTypes.func, interactionData: PropTypes.object.isRequired, userResponse: PropTypes.object.isRequired, readOnly: PropTypes.bool, styles: PropTypes.object }; var FillBlankTakeWithStyles = withStyleOverrides(generateStyle, generateComponentTheme)(FillBlankTake); FillBlankTakeWithStyles.displayName = 'FillBlankTake'; FillBlankTakeWithStyles.componentId = "Quizzes".concat(FillBlankTake.displayName); FillBlankTakeWithStyles.originalType = FillBlankTake; export default FillBlankTakeWithStyles;