UNPKG

@instructure/quiz-interactions

Version:

A React UI component Library for quiz interaction types.

177 lines (175 loc) • 7.47 kB
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck"; import _createClass from "@babel/runtime/helpers/esm/createClass"; import _possibleConstructorReturn from "@babel/runtime/helpers/esm/possibleConstructorReturn"; import _getPrototypeOf from "@babel/runtime/helpers/esm/getPrototypeOf"; import _inherits from "@babel/runtime/helpers/esm/inherits"; import _defineProperty from "@babel/runtime/helpers/esm/defineProperty"; 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 _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else 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 _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 = _getPrototypeOf(derived); return _possibleConstructorReturn(_this, isNativeReflectConstruct() ? Reflect.construct(derived, args || [], _getPrototypeOf(_this).constructor) : derived.apply(_this, args)); } import React, { Component } from 'react'; import PropTypes from 'prop-types'; import get from 'lodash/get'; import isEqual from 'lodash/isEqual'; import pick from 'lodash/pick'; // TODO: Kill this HOC and use composition instead. This thing is a nightmare to maintain... /** * Higher Order Component used in Edit views to pass generic helper functions */ export default function withEditTools(WrappedComponent) { var _Wrapper; var Wrapper = /*#__PURE__*/function (_Component) { function Wrapper() { var _this2; _classCallCheck(this, Wrapper); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this2 = _callSuper(this, Wrapper, [].concat(args)); _defineProperty(_this2, "node", null); /** * default handling of stem changes */ _defineProperty(_this2, "handleDescriptionChange", function (itemBody) { return _this2.props.changeItemState({ itemBody: itemBody }); }); /** * helper function that gives out errors in instui format */ _defineProperty(_this2, "getErrors", function (path) { var fallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; var errors = get(_this2.props.errors, path); if (errors != null && _this2.props.errorsAreShowing) { return formatErrors(errors); } return fallback; }); _defineProperty(_this2, "getWrappedComponent", function () { return _this2.node; }); _defineProperty(_this2, "handleRef", function (node) { _this2.node = node; }); return _this2; } _inherits(Wrapper, _Component); return _createClass(Wrapper, [{ key: "componentDidMount", value: // If the props passed to the component on mount result in validation // errors, call the changeItemState callback with the validation errors to // notify the parent component function componentDidMount() { var itemState = this.getItemState(); if (Object.keys(itemState.errors).length > 0) { this.props.changeItemState(itemState); } } }, { key: "componentDidUpdate", value: function componentDidUpdate(prevProps) { var itemState = this.getItemState(); if (!isEqual(itemState.errors, prevProps.errors)) { this.props.changeItemState(itemState); } } }, { key: "getItem", value: function getItem() { var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.props; return pick(props, ['calculatorType', 'interactionData', 'itemBody', 'properties', 'scoringAlgorithm', 'scoringData']); } }, { key: "getItemErrors", value: function getItemErrors(item) { return WrappedComponent.interactionType.getErrors(item); } }, { key: "getItemState", value: function getItemState() { var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.props; var item = this.getItem(props); var errors = this.getItemErrors(item); return _objectSpread(_objectSpread({}, item), {}, { errors: errors }); } }, { key: "render", value: /** * render the decorated component, passing helpers through props */ function render() { return /*#__PURE__*/React.createElement(WrappedComponent, Object.assign({ ref: this.handleRef, onDescriptionChange: this.handleDescriptionChange, getErrors: this.getErrors }, this.props)); } }]); }(Component); _Wrapper = Wrapper; _defineProperty(Wrapper, "displayName", "".concat(_Wrapper.name, "(").concat(WrappedComponent.displayName, ")")); // [jsimon]: I originally tried to switch these PropTypes.object calls to WrappedComponent.propTypes.<name> but // these props don't exist on every edit component. To make matters worse, their shape isn't consistent so we can't // make these more specific. _defineProperty(Wrapper, "propTypes", { changeItemState: PropTypes.func.isRequired, errors: PropTypes.object, errorsAreShowing: PropTypes.bool, interactionData: PropTypes.object, itemBody: PropTypes.string, properties: PropTypes.object, scoringData: PropTypes.object, children: PropTypes.node }); _defineProperty(Wrapper, "defaultProps", { errors: void 0, errorsAreShowing: void 0, interactionData: void 0, itemBody: void 0, properties: void 0, scoringData: void 0, children: void 0 }); Wrapper.WrappedComponent = WrappedComponent; return Wrapper; } // These can be included by components that use withEditTools, to provide // propType validation without including these private, internal props in the // auto-generated documentation. withEditTools.injectedProps = { getErrors: PropTypes.func.isRequired, onDescriptionChange: PropTypes.func.isRequired }; function formatErrors(node) { if (typeof node === 'string') { return { text: node, type: 'error' }; } else if (Array.isArray(node)) { return node.map(formatErrors); } else if (typeof node === 'object') { return Object.keys(node).reduce(function (obj, key) { return _objectSpread(_objectSpread({}, obj), {}, _defineProperty({}, key, formatErrors(node[key]))); }, {}); } return node; }