UNPKG

@instructure/quiz-interactions

Version:

A React UI component Library for quiz interaction types.

207 lines (203 loc) • 8.69 kB
/* eslint-disable react/jsx-no-bind */ 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_with_holes(arr) { if (Array.isArray(arr)) return arr; } function _iterable_to_array_limit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){ _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally{ try { if (!_n && _i["return"] != null) _i["return"](); } finally{ if (_d) throw _e; } } return _arr; } function _non_iterable_rest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _sliced_to_array(arr, i) { return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest(); } 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, { useState, useEffect, useRef, useContext, useCallback } from 'react'; import PropTypes from 'prop-types'; import { ScreenReaderContent } from '@instructure/ui-a11y-content'; import { ScientificNumberInput } from '@instructure/quiz-number-input'; import { Decimal } from '@instructure/quiz-i18n'; import { ItemBodyWrapper, RichContentRenderer } from '@instructure/quiz-rce'; import { View } from '@instructure/ui-view'; import t from '@instructure/quiz-i18n/format-message'; import { Text } from '@instructure/ui-text'; import { ApplyLocaleContext } from '@instructure/ui-i18n'; import { parseSeparators } from '@instructure/quiz-common'; import { Alert } from '@instructure/ui-alerts'; /** --- category: Numeric --- Numeric Take component ```jsx_example function Example (props) { const exampleProps = { itemBody: 'x is an integer and 9 < x^2 < 99. What\'s the max value of x, minus the minimum value of x', userResponse: { value: '18' } } return ( <NumericTake {...exampleProps} {...props} /> ) } <SettingsSwitcher locales={LOCALES}> <TakeStateProvider> <Example /> </TakeStateProvider> </SettingsSwitcher> ``` **/ var invalidMessage = { text: t('Answer must be a number. Remove any symbols or units.'), type: 'error' }; function NumericTake(param) { var _param_displayValidationWarning = param.displayValidationWarning, displayValidationWarning = _param_displayValidationWarning === void 0 ? false : _param_displayValidationWarning, itemBody = param.itemBody, handleResponseUpdate = param.handleResponseUpdate, _param_userResponse = param.userResponse, userResponse = _param_userResponse === void 0 ? { value: null } : _param_userResponse, separatorConfig = param.separatorConfig; var context = useContext(ApplyLocaleContext); var _useState = _sliced_to_array(useState(null), 2), value = _useState[0], setValue = _useState[1]; var _useState1 = _sliced_to_array(useState(null), 2), normalized = _useState1[0], setNormalized = _useState1[1]; var _useState2 = _sliced_to_array(useState([]), 2), messages = _useState2[0], setMessages = _useState2[1]; var _useState3 = _sliced_to_array(useState(false), 2), showSeparatorChangeWarning = _useState3[0], setShowSeparatorChangeWarning = _useState3[1]; var _useState4 = _sliced_to_array(useState(false), 2), separatorConfigInitialized = _useState4[0], setSeparatorConfigInitialized = _useState4[1]; var _useState5 = _sliced_to_array(useState(false), 2), valueInitialized = _useState5[0], setValueInitialized = _useState5[1]; var hasNormalizedAfterInitialization = useRef(false); // Set up decimal delimiters on mount useEffect(function() { Decimal.accountSettingDelimiters = separatorConfig ? parseSeparators(separatorConfig) : null; setSeparatorConfigInitialized(true); }, [ separatorConfig ]); // Update initial value using the updated locale settings useEffect(function() { if (!separatorConfigInitialized || valueInitialized) { return; } try { var newValue = Decimal.toLocaleStringIfValid(userResponse.value, context.locale); setValue(newValue); } catch (e) { setValue(userResponse.value); } setValueInitialized(true); }, [ context.locale, valueInitialized, separatorConfigInitialized, userResponse.value ]); var updateLogs = function(currentValue, currentNormalized) { // If the response isn't a number, call the handler with the raw response var invalid = displayValidationWarning && currentValue && currentNormalized == null; var update = currentNormalized == null ? currentValue : currentNormalized; if (update !== userResponse.value) { handleResponseUpdate(update, null, invalid); } }; var checkInvalid = useCallback(function(currentValue, currentNormalized) { if (displayValidationWarning && currentValue && currentNormalized == null) { setMessages([ invalidMessage ]); } }, [ displayValidationWarning ]); var handleInitialNormalization = function(currentNormalized) { setNormalized(currentNormalized); if (!hasNormalizedAfterInitialization.current) { checkInvalid(value, currentNormalized); if (displayValidationWarning && value && currentNormalized == null) { var update = currentNormalized == null ? value : currentNormalized; handleResponseUpdate(update, null, true); } } hasNormalizedAfterInitialization.current = true; }; var handleResponseChange = function(_event, newValue, newNormalized) { setValue(newValue); setNormalized(newNormalized); setMessages([]); updateLogs(newValue, newNormalized); }; var handleResponseBlur = function(_event, hasFormattingChanged) { checkInvalid(value, normalized); updateLogs(value, normalized); setShowSeparatorChangeWarning(hasFormattingChanged); }; if (!separatorConfigInitialized || !valueInitialized) { return null; } return /*#__PURE__*/ React.createElement(ItemBodyWrapper, { itemBody: itemBody }, /*#__PURE__*/ React.createElement("div", { className: "fs-mask" }, /*#__PURE__*/ React.createElement(ScientificNumberInput, { inputType: "text", messages: messages, renderLabel: /*#__PURE__*/ React.createElement(View, null, /*#__PURE__*/ React.createElement(Text, { "aria-hidden": true }, t('Answer')), /*#__PURE__*/ React.createElement(ScreenReaderContent, null, /*#__PURE__*/ React.createElement(RichContentRenderer, { content: itemBody }))), onChange: handleResponseChange, onBlur: handleResponseBlur, value: value, onInitialNormalization: handleInitialNormalization, autoComplete: "off" }), showSeparatorChangeWarning && /*#__PURE__*/ React.createElement(Alert, { variant: "info", hasShadow: false, transition: "none" }, t('Decimal separator auto-adjusted. Verify your entry! (correct format: e.g. {example})', { example: Decimal.toLocaleString('1000.12', context.locale) })))); } NumericTake.propTypes = { displayValidationWarning: PropTypes.bool, itemBody: PropTypes.string.isRequired, handleResponseUpdate: PropTypes.func.isRequired, userResponse: PropTypes.shape({ value: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]) }), separatorConfig: PropTypes.shape({ decimalSeparator: PropTypes.string, thousandSeparator: PropTypes.string }) }; export default NumericTake;