@instructure/quiz-interactions
Version:
A React UI component Library for quiz interaction types.
207 lines (203 loc) • 8.69 kB
JavaScript
/* 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;