@instructure/quiz-core 20.16.1-rc.8 → 20.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,24 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [20.17.0](https://gerrit.instructure.com/quizzes-ui/compare/v20.16.0...v20.17.0) (2024-08-06)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * **a11y:** correct timer command for OS X ([80dd509](https://gerrit.instructure.com/quizzes-ui/commits/80dd509d088767c8d222f534bbf703a95c183760))
12
+ * **a11y:** Focus isn't trapped inside of tray ([073433a](https://gerrit.instructure.com/quizzes-ui/commits/073433a328d7716fc320698f01fd6f39523ff5f5))
13
+ * **a11y:** hide instructions after first question for screen reader ([df1b9be](https://gerrit.instructure.com/quizzes-ui/commits/df1b9bee393ed2585ecf8d3ff526e93bfe07e7b8))
14
+ * **a11y:** localize strings for shortcut command ([521b894](https://gerrit.instructure.com/quizzes-ui/commits/521b894fd318297561afdcd7a76d5c2f5d5028e2))
15
+ * **a11y:** make access code success message polite ([16f4c9e](https://gerrit.instructure.com/quizzes-ui/commits/16f4c9eaacdcb4f53aeb94b4acce383ded3fe00a))
16
+ * **a11y:** move user's focus to topmost error field ([87e7691](https://gerrit.instructure.com/quizzes-ui/commits/87e7691b12c61f2e48b34923c61445242309181a))
17
+ * **alerts:** make all alerts assertive by default ([18b632a](https://gerrit.instructure.com/quizzes-ui/commits/18b632a902fb06139b6b080bc39f5c750c984f43))
18
+ * **ResultStimulus:** add width constraint ([7ddad6d](https://gerrit.instructure.com/quizzes-ui/commits/7ddad6d3e06a83b7348f630dba07c3420bcc8b81))
19
+
20
+
21
+
22
+
23
+
6
24
  # [20.16.0](https://gerrit.instructure.com/quizzes-ui/compare/v20.15.0...v20.16.0) (2024-07-08)
7
25
 
8
26
 
@@ -80,6 +80,10 @@ export var QuizEntry = (_dec = withStyle(generateStyle, generateComponentTheme),
80
80
  _this.props.changeQuizEntryPoints(_this.props.quizEntry.id, points);
81
81
  };
82
82
 
83
+ _this.handleRef = function (node) {
84
+ _this.itemEditArea = node;
85
+ };
86
+
83
87
  _this.renderPrintableItemBankSample = function (sampleItem, index) {
84
88
  var quizEntry = QuizEntryRecord.create(sampleItem.toObject());
85
89
  var entryMutable = quizEntry.entry.toJS();
@@ -166,7 +170,8 @@ export var QuizEntry = (_dec = withStyle(generateStyle, generateComponentTheme),
166
170
  initialFocusId: this.props.initialFocusId,
167
171
  handleValidationErrorsFromApi: this.props.handleValidationErrorsFromApi,
168
172
  clearValidationErrorsFromApi: this.props.clearValidationErrorsFromApi,
169
- haveValidationErrorsFromApi: Boolean(Object.values(this.props.validationErrorsFromApi).length)
173
+ haveValidationErrorsFromApi: Boolean(Object.values(this.props.validationErrorsFromApi).length),
174
+ itemEditArea: this.itemEditArea
170
175
  }, pick(this.props, ['displayPosition', 'guid', 'draggingOnBuild', 'newHoverPosition', 'quizEntry', 'quizEntries', 'quizId', 'isContentLockedByBlueprint', 'setUi', 'switchOffEditing', 'switchOnEditing', 'shouldClone', 'scrollKey', 'editQuizEntryToggle', 'onEditQuizEntryToggle', 'stimulusOrientation']));
171
176
  }
172
177
  }, {
@@ -321,7 +326,8 @@ export var QuizEntry = (_dec = withStyle(generateStyle, generateComponentTheme),
321
326
  key: "render",
322
327
  value: function render() {
323
328
  return this.props.connectDropTarget(jsx("div", {
324
- tabIndex: "-1"
329
+ tabIndex: "-1",
330
+ ref: this.handleRef
325
331
  }, this.renderQuizEntryByType()));
326
332
  }
327
333
  }]);
@@ -211,7 +211,8 @@ export var QuizEntryEditFooter = (_dec = withStyle(generateStyle, generateCompon
211
211
  guid: this.props.guid,
212
212
  isValid: this.props.isValid,
213
213
  submitHandler: this.props.successfulSubmit,
214
- initialFocusId: this.props.initialFocusId
214
+ initialFocusId: this.props.initialFocusId,
215
+ itemEditArea: this.props.itemEditArea
215
216
  });
216
217
  }
217
218
  }, {
@@ -245,6 +246,7 @@ export var QuizEntryEditFooter = (_dec = withStyle(generateStyle, generateCompon
245
246
  guid: PropTypes.string.isRequired,
246
247
  initialFocusId: PropTypes.string,
247
248
  isValid: PropTypes.bool.isRequired,
249
+ itemEditArea: PropTypes.object,
248
250
  openModal: PropTypes.func.isRequired,
249
251
  quizEntry: ImmutablePropTypes.record.isRequired,
250
252
  setUi: PropTypes.func.isRequired,
@@ -259,6 +261,7 @@ export var QuizEntryEditFooter = (_dec = withStyle(generateStyle, generateCompon
259
261
  alternativeRightFooter: null,
260
262
  disableSubmit: false,
261
263
  initialFocusId: null,
264
+ itemEditArea: null,
262
265
  shouldClone: false
263
266
  }, _temp)) || _class);
264
267
  export default QuizEntryEditFooter;
@@ -370,7 +370,7 @@ var QuizEntryEdit = (_dec = withStyle(generateStyle, generateComponentTheme), _d
370
370
  value: function renderFooter() {
371
371
  var isItemOrBankEntry = this.props.quizEntry.isItem || this.props.quizEntry.isBankEntry;
372
372
  if (!(isItemOrBankEntry || this.props.disabledForRegrade)) return;
373
- var footerProps = pick(this.props, ['alternativeRightFooter', 'changeQuizEntryPoints', 'clearTemporaryItem', 'displayPosition', 'entry', 'guid', 'initialFocusId', 'openModal', 'quizEntry', 'setUi', 'shouldClone', 'workingQuizEntry']);
373
+ var footerProps = pick(this.props, ['alternativeRightFooter', 'changeQuizEntryPoints', 'clearTemporaryItem', 'displayPosition', 'entry', 'guid', 'initialFocusId', 'itemEditArea', 'openModal', 'quizEntry', 'setUi', 'shouldClone', 'workingQuizEntry']);
374
374
  return jsx(QuizEntryEditFooter, Object.assign({
375
375
  clearChanges: this.clearChanges,
376
376
  isValid: this.isValid(),
@@ -466,6 +466,7 @@ var QuizEntryEdit = (_dec = withStyle(generateStyle, generateComponentTheme), _d
466
466
  // from connected component
467
467
  initialFocusId: PropTypes.string,
468
468
  isOccluded: PropTypes.bool,
469
+ itemEditArea: PropTypes.object,
469
470
  name: PropTypes.string,
470
471
  newActiveBank: PropTypes.func,
471
472
  nextQuizEntry: ImmutablePropTypes.map,
@@ -501,6 +502,7 @@ var QuizEntryEdit = (_dec = withStyle(generateStyle, generateComponentTheme), _d
501
502
  haveValidationErrorsFromApi: false,
502
503
  initialFocusId: null,
503
504
  isOccluded: false,
505
+ itemEditArea: null,
504
506
  name: null,
505
507
  nextQuizEntry: null,
506
508
  newActiveBank: null,
@@ -7,7 +7,8 @@ export function addAlert(_ref) {
7
7
  removeIn = _ref$removeIn === void 0 ? DEFAULT_ALERT_TIME : _ref$removeIn,
8
8
  _ref$guid = _ref.guid,
9
9
  guid = _ref$guid === void 0 ? uuid() : _ref$guid,
10
- politeness = _ref.politeness;
10
+ _ref$politeness = _ref.politeness,
11
+ politeness = _ref$politeness === void 0 ? ASSERTIVE : _ref$politeness;
11
12
  return {
12
13
  type: ADD_ALERT,
13
14
  payload: {
@@ -46,8 +47,7 @@ export function addInfo(message) {
46
47
  variant: 'info'
47
48
  });
48
49
  }
49
- export function screenreaderNotification(message) {
50
- var politeness = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : ASSERTIVE;
50
+ export function screenreaderNotification(message, politeness) {
51
51
  return addAlert({
52
52
  message: message,
53
53
  variant: 'screenreader',
@@ -112,7 +112,8 @@ export var Timer = (_dec = withStyle(generateStyle, generateComponentTheme), _de
112
112
  }, {
113
113
  key: "renderHelpScreenreaderText",
114
114
  value: function renderHelpScreenreaderText() {
115
- var shortcutKey = platform.os.toString().startsWith('OS X') ? 'Option+Shift+T' : 'Alt+Shift+T';
115
+ // command based on operating system
116
+ var shortcutKey = platform.os.toString().startsWith('OS X') ? t('Option+Shift+T') : t('Alt+Shift+T');
116
117
  return jsx(ScreenReaderContent, null, t('During the quiz, press {shortcutKey} to have the remaining time read', {
117
118
  shortcutKey: shortcutKey
118
119
  }));
@@ -7,6 +7,7 @@ import _createSuper from "@babel/runtime/helpers/esm/createSuper";
7
7
  import React, { Component } from 'react';
8
8
  import PropTypes from 'prop-types';
9
9
  import ImmutablePropTypes from 'react-immutable-proptypes';
10
+ import ReactDOM from 'react-dom';
10
11
  import { Button } from '@instructure/ui-buttons';
11
12
  import { View } from '@instructure/ui-view';
12
13
  import { API_INPUT_VALIDATION_ERROR } from '@instructure/quiz-common';
@@ -100,21 +101,59 @@ export var EntrySave = /*#__PURE__*/function (_Component) {
100
101
  }());
101
102
  };
102
103
 
103
- _this.onSubmit = function (e) {
104
- e.preventDefault();
104
+ _this.onSubmit = /*#__PURE__*/function () {
105
+ var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(e) {
106
+ return _regeneratorRuntime.wrap(function _callee2$(_context2) {
107
+ while (1) {
108
+ switch (_context2.prev = _context2.next) {
109
+ case 0:
110
+ e.preventDefault();
111
+
112
+ if (!_this.props.isValid) {
113
+ _context2.next = 5;
114
+ break;
115
+ }
116
+
117
+ if (_this.props.checkBankedContentShareabilityEnabled && _this.props.shouldValidateShareableContent) {
118
+ _this.confirmShareableContent();
119
+ } else {
120
+ _this.successfulSubmit();
121
+ }
122
+
123
+ _context2.next = 10;
124
+ break;
125
+
126
+ case 5:
127
+ _this.createScreenReaderNotification();
128
+
129
+ _context2.next = 8;
130
+ return _this.props.showError(_this.props.guid);
105
131
 
106
- if (_this.props.isValid) {
107
- if (_this.props.checkBankedContentShareabilityEnabled && _this.props.shouldValidateShareableContent) {
108
- _this.confirmShareableContent();
109
- } else {
110
- _this.successfulSubmit();
111
- }
112
- } else {
113
- _this.createScreenReaderNotification();
132
+ case 8:
133
+ _this.props.clearNextQuizEntry();
114
134
 
115
- _this.props.showError(_this.props.guid);
135
+ _this.focusFirstErrorField();
116
136
 
117
- _this.props.clearNextQuizEntry();
137
+ case 10:
138
+ case "end":
139
+ return _context2.stop();
140
+ }
141
+ }
142
+ }, _callee2);
143
+ }));
144
+
145
+ return function (_x2) {
146
+ return _ref2.apply(this, arguments);
147
+ };
148
+ }();
149
+
150
+ _this.focusFirstErrorField = function () {
151
+ var itemEditArea = _this.props.itemEditArea;
152
+
153
+ if (itemEditArea) {
154
+ var editArea = ReactDOM.findDOMNode(itemEditArea);
155
+ var firstErrorField = editArea === null || editArea === void 0 ? void 0 : editArea.querySelector('[aria-invalid="true"]');
156
+ firstErrorField && firstErrorField.focus();
118
157
  }
119
158
  };
120
159
 
@@ -152,24 +191,24 @@ export var EntrySave = /*#__PURE__*/function (_Component) {
152
191
  }, {
153
192
  key: "successfulSubmit",
154
193
  value: function () {
155
- var _successfulSubmit = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
194
+ var _successfulSubmit = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
156
195
  var validationResult;
157
- return _regeneratorRuntime.wrap(function _callee2$(_context2) {
196
+ return _regeneratorRuntime.wrap(function _callee3$(_context3) {
158
197
  while (1) {
159
- switch (_context2.prev = _context2.next) {
198
+ switch (_context3.prev = _context3.next) {
160
199
  case 0:
161
200
  this.setState({
162
201
  canSubmit: false
163
202
  });
164
- _context2.prev = 1;
165
- _context2.next = 4;
203
+ _context3.prev = 1;
204
+ _context3.next = 4;
166
205
  return this.props.submitHandler();
167
206
 
168
207
  case 4:
169
- validationResult = _context2.sent;
208
+ validationResult = _context3.sent;
170
209
 
171
210
  if (!(validationResult === API_INPUT_VALIDATION_ERROR)) {
172
- _context2.next = 8;
211
+ _context3.next = 8;
173
212
  break;
174
213
  }
175
214
 
@@ -177,16 +216,16 @@ export var EntrySave = /*#__PURE__*/function (_Component) {
177
216
  throw new Error('User input validation error received from API.');
178
217
 
179
218
  case 8:
180
- _context2.next = 14;
219
+ _context3.next = 14;
181
220
  break;
182
221
 
183
222
  case 10:
184
- _context2.prev = 10;
185
- _context2.t0 = _context2["catch"](1);
223
+ _context3.prev = 10;
224
+ _context3.t0 = _context3["catch"](1);
186
225
  this.setState({
187
226
  canSubmit: true
188
227
  });
189
- return _context2.abrupt("return");
228
+ return _context3.abrupt("return");
190
229
 
191
230
  case 14:
192
231
  this.props.switchOffEditing();
@@ -195,10 +234,10 @@ export var EntrySave = /*#__PURE__*/function (_Component) {
195
234
 
196
235
  case 17:
197
236
  case "end":
198
- return _context2.stop();
237
+ return _context3.stop();
199
238
  }
200
239
  }
201
- }, _callee2, this, [[1, 10]]);
240
+ }, _callee3, this, [[1, 10]]);
202
241
  }));
203
242
 
204
243
  function successfulSubmit() {
@@ -247,6 +286,7 @@ EntrySave.propTypes = {
247
286
  hideError: PropTypes.func.isRequired,
248
287
  initialFocusId: PropTypes.string,
249
288
  isValid: PropTypes.bool.isRequired,
289
+ itemEditArea: PropTypes.object,
250
290
  showError: PropTypes.func.isRequired,
251
291
  screenreaderNotification: PropTypes.func.isRequired,
252
292
  shouldValidateShareableContent: PropTypes.bool,
@@ -264,6 +304,7 @@ EntrySave.defaultProps = {
264
304
  disableSubmit: false,
265
305
  guid: null,
266
306
  initialFocusId: null,
307
+ itemEditArea: null,
267
308
  shouldValidateShareableContent: false
268
309
  };
269
310
  export default EntrySave;
@@ -57,7 +57,8 @@ var generateStyle = function generateStyle(componentTheme, props) {
57
57
  width: '100%'
58
58
  })),
59
59
  stimulusItem: {
60
- flex: '1 1 auto'
60
+ flex: '1 1 auto',
61
+ width: '100%'
61
62
  },
62
63
  stimulusGroup: _objectSpread(_objectSpread({
63
64
  display: 'flex',
@@ -118,6 +118,10 @@ var QuizEntry = (_dec = (0, _emotion.withStyle)(_styles.default, _theme.default)
118
118
  _this.props.changeQuizEntryPoints(_this.props.quizEntry.id, points);
119
119
  };
120
120
 
121
+ _this.handleRef = function (node) {
122
+ _this.itemEditArea = node;
123
+ };
124
+
121
125
  _this.renderPrintableItemBankSample = function (sampleItem, index) {
122
126
  var quizEntry = _QuizEntry.default.create(sampleItem.toObject());
123
127
 
@@ -205,7 +209,8 @@ var QuizEntry = (_dec = (0, _emotion.withStyle)(_styles.default, _theme.default)
205
209
  initialFocusId: this.props.initialFocusId,
206
210
  handleValidationErrorsFromApi: this.props.handleValidationErrorsFromApi,
207
211
  clearValidationErrorsFromApi: this.props.clearValidationErrorsFromApi,
208
- haveValidationErrorsFromApi: Boolean(Object.values(this.props.validationErrorsFromApi).length)
212
+ haveValidationErrorsFromApi: Boolean(Object.values(this.props.validationErrorsFromApi).length),
213
+ itemEditArea: this.itemEditArea
209
214
  }, (0, _pick.default)(this.props, ['displayPosition', 'guid', 'draggingOnBuild', 'newHoverPosition', 'quizEntry', 'quizEntries', 'quizId', 'isContentLockedByBlueprint', 'setUi', 'switchOffEditing', 'switchOnEditing', 'shouldClone', 'scrollKey', 'editQuizEntryToggle', 'onEditQuizEntryToggle', 'stimulusOrientation']));
210
215
  }
211
216
  }, {
@@ -360,7 +365,8 @@ var QuizEntry = (_dec = (0, _emotion.withStyle)(_styles.default, _theme.default)
360
365
  key: "render",
361
366
  value: function render() {
362
367
  return this.props.connectDropTarget((0, _emotion.jsx)("div", {
363
- tabIndex: "-1"
368
+ tabIndex: "-1",
369
+ ref: this.handleRef
364
370
  }, this.renderQuizEntryByType()));
365
371
  }
366
372
  }]);
@@ -238,7 +238,8 @@ var QuizEntryEditFooter = (_dec = (0, _emotion.withStyle)(_styles.default, _them
238
238
  guid: this.props.guid,
239
239
  isValid: this.props.isValid,
240
240
  submitHandler: this.props.successfulSubmit,
241
- initialFocusId: this.props.initialFocusId
241
+ initialFocusId: this.props.initialFocusId,
242
+ itemEditArea: this.props.itemEditArea
242
243
  });
243
244
  }
244
245
  }, {
@@ -271,6 +272,7 @@ var QuizEntryEditFooter = (_dec = (0, _emotion.withStyle)(_styles.default, _them
271
272
  guid: _propTypes.default.string.isRequired,
272
273
  initialFocusId: _propTypes.default.string,
273
274
  isValid: _propTypes.default.bool.isRequired,
275
+ itemEditArea: _propTypes.default.object,
274
276
  openModal: _propTypes.default.func.isRequired,
275
277
  quizEntry: _reactImmutableProptypes.default.record.isRequired,
276
278
  setUi: _propTypes.default.func.isRequired,
@@ -285,6 +287,7 @@ var QuizEntryEditFooter = (_dec = (0, _emotion.withStyle)(_styles.default, _them
285
287
  alternativeRightFooter: null,
286
288
  disableSubmit: false,
287
289
  initialFocusId: null,
290
+ itemEditArea: null,
288
291
  shouldClone: false
289
292
  }, _temp)) || _class);
290
293
  exports.QuizEntryEditFooter = QuizEntryEditFooter;
@@ -402,7 +402,7 @@ var QuizEntryEdit = (_dec = (0, _emotion.withStyle)(_styles.default, _theme.defa
402
402
  value: function renderFooter() {
403
403
  var isItemOrBankEntry = this.props.quizEntry.isItem || this.props.quizEntry.isBankEntry;
404
404
  if (!(isItemOrBankEntry || this.props.disabledForRegrade)) return;
405
- var footerProps = (0, _pick.default)(this.props, ['alternativeRightFooter', 'changeQuizEntryPoints', 'clearTemporaryItem', 'displayPosition', 'entry', 'guid', 'initialFocusId', 'openModal', 'quizEntry', 'setUi', 'shouldClone', 'workingQuizEntry']);
405
+ var footerProps = (0, _pick.default)(this.props, ['alternativeRightFooter', 'changeQuizEntryPoints', 'clearTemporaryItem', 'displayPosition', 'entry', 'guid', 'initialFocusId', 'itemEditArea', 'openModal', 'quizEntry', 'setUi', 'shouldClone', 'workingQuizEntry']);
406
406
  return (0, _emotion.jsx)(_index4.default, Object.assign({
407
407
  clearChanges: this.clearChanges,
408
408
  isValid: this.isValid(),
@@ -497,6 +497,7 @@ var QuizEntryEdit = (_dec = (0, _emotion.withStyle)(_styles.default, _theme.defa
497
497
  // from connected component
498
498
  initialFocusId: _propTypes.default.string,
499
499
  isOccluded: _propTypes.default.bool,
500
+ itemEditArea: _propTypes.default.object,
500
501
  name: _propTypes.default.string,
501
502
  newActiveBank: _propTypes.default.func,
502
503
  nextQuizEntry: _reactImmutableProptypes.default.map,
@@ -532,6 +533,7 @@ var QuizEntryEdit = (_dec = (0, _emotion.withStyle)(_styles.default, _theme.defa
532
533
  haveValidationErrorsFromApi: false,
533
534
  initialFocusId: null,
534
535
  isOccluded: false,
536
+ itemEditArea: null,
535
537
  name: null,
536
538
  nextQuizEntry: null,
537
539
  newActiveBank: null,
@@ -22,7 +22,8 @@ function addAlert(_ref) {
22
22
  removeIn = _ref$removeIn === void 0 ? _quizCommon.DEFAULT_ALERT_TIME : _ref$removeIn,
23
23
  _ref$guid = _ref.guid,
24
24
  guid = _ref$guid === void 0 ? (0, _uuid.v4)() : _ref$guid,
25
- politeness = _ref.politeness;
25
+ _ref$politeness = _ref.politeness,
26
+ politeness = _ref$politeness === void 0 ? _quizCommon.ASSERTIVE : _ref$politeness;
26
27
  return {
27
28
  type: _quizCommon.ADD_ALERT,
28
29
  payload: {
@@ -66,8 +67,7 @@ function addInfo(message) {
66
67
  });
67
68
  }
68
69
 
69
- function screenreaderNotification(message) {
70
- var politeness = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : _quizCommon.ASSERTIVE;
70
+ function screenreaderNotification(message, politeness) {
71
71
  return addAlert({
72
72
  message: message,
73
73
  variant: 'screenreader',
@@ -139,7 +139,8 @@ var Timer = (_dec = (0, _emotion.withStyle)(_styles.default, _theme.default), _d
139
139
  }, {
140
140
  key: "renderHelpScreenreaderText",
141
141
  value: function renderHelpScreenreaderText() {
142
- var shortcutKey = platform.os.toString().startsWith('OS X') ? 'Option+Shift+T' : 'Alt+Shift+T';
142
+ // command based on operating system
143
+ var shortcutKey = platform.os.toString().startsWith('OS X') ? (0, _formatMessage.default)('Option+Shift+T') : (0, _formatMessage.default)('Alt+Shift+T');
143
144
  return (0, _emotion.jsx)(_uiA11yContent.ScreenReaderContent, null, (0, _formatMessage.default)('During the quiz, press {shortcutKey} to have the remaining time read', {
144
145
  shortcutKey: shortcutKey
145
146
  }));
@@ -27,6 +27,8 @@ var _propTypes = _interopRequireDefault(require("prop-types"));
27
27
 
28
28
  var _reactImmutableProptypes = _interopRequireDefault(require("react-immutable-proptypes"));
29
29
 
30
+ var _reactDom = _interopRequireDefault(require("react-dom"));
31
+
30
32
  var _uiButtons = require("@instructure/ui-buttons");
31
33
 
32
34
  var _uiView = require("@instructure/ui-view");
@@ -125,21 +127,60 @@ var EntrySave = /*#__PURE__*/function (_Component) {
125
127
  }());
126
128
  };
127
129
 
128
- _this.onSubmit = function (e) {
129
- e.preventDefault();
130
+ _this.onSubmit = /*#__PURE__*/function () {
131
+ var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(e) {
132
+ return _regenerator.default.wrap(function _callee2$(_context2) {
133
+ while (1) {
134
+ switch (_context2.prev = _context2.next) {
135
+ case 0:
136
+ e.preventDefault();
137
+
138
+ if (!_this.props.isValid) {
139
+ _context2.next = 5;
140
+ break;
141
+ }
142
+
143
+ if (_this.props.checkBankedContentShareabilityEnabled && _this.props.shouldValidateShareableContent) {
144
+ _this.confirmShareableContent();
145
+ } else {
146
+ _this.successfulSubmit();
147
+ }
148
+
149
+ _context2.next = 10;
150
+ break;
151
+
152
+ case 5:
153
+ _this.createScreenReaderNotification();
154
+
155
+ _context2.next = 8;
156
+ return _this.props.showError(_this.props.guid);
130
157
 
131
- if (_this.props.isValid) {
132
- if (_this.props.checkBankedContentShareabilityEnabled && _this.props.shouldValidateShareableContent) {
133
- _this.confirmShareableContent();
134
- } else {
135
- _this.successfulSubmit();
136
- }
137
- } else {
138
- _this.createScreenReaderNotification();
158
+ case 8:
159
+ _this.props.clearNextQuizEntry();
160
+
161
+ _this.focusFirstErrorField();
162
+
163
+ case 10:
164
+ case "end":
165
+ return _context2.stop();
166
+ }
167
+ }
168
+ }, _callee2);
169
+ }));
170
+
171
+ return function (_x2) {
172
+ return _ref2.apply(this, arguments);
173
+ };
174
+ }();
175
+
176
+ _this.focusFirstErrorField = function () {
177
+ var itemEditArea = _this.props.itemEditArea;
139
178
 
140
- _this.props.showError(_this.props.guid);
179
+ if (itemEditArea) {
180
+ var editArea = _reactDom.default.findDOMNode(itemEditArea);
141
181
 
142
- _this.props.clearNextQuizEntry();
182
+ var firstErrorField = editArea === null || editArea === void 0 ? void 0 : editArea.querySelector('[aria-invalid="true"]');
183
+ firstErrorField && firstErrorField.focus();
143
184
  }
144
185
  };
145
186
 
@@ -177,24 +218,24 @@ var EntrySave = /*#__PURE__*/function (_Component) {
177
218
  }, {
178
219
  key: "successfulSubmit",
179
220
  value: function () {
180
- var _successfulSubmit = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2() {
221
+ var _successfulSubmit = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3() {
181
222
  var validationResult;
182
- return _regenerator.default.wrap(function _callee2$(_context2) {
223
+ return _regenerator.default.wrap(function _callee3$(_context3) {
183
224
  while (1) {
184
- switch (_context2.prev = _context2.next) {
225
+ switch (_context3.prev = _context3.next) {
185
226
  case 0:
186
227
  this.setState({
187
228
  canSubmit: false
188
229
  });
189
- _context2.prev = 1;
190
- _context2.next = 4;
230
+ _context3.prev = 1;
231
+ _context3.next = 4;
191
232
  return this.props.submitHandler();
192
233
 
193
234
  case 4:
194
- validationResult = _context2.sent;
235
+ validationResult = _context3.sent;
195
236
 
196
237
  if (!(validationResult === _quizCommon.API_INPUT_VALIDATION_ERROR)) {
197
- _context2.next = 8;
238
+ _context3.next = 8;
198
239
  break;
199
240
  }
200
241
 
@@ -202,16 +243,16 @@ var EntrySave = /*#__PURE__*/function (_Component) {
202
243
  throw new Error('User input validation error received from API.');
203
244
 
204
245
  case 8:
205
- _context2.next = 14;
246
+ _context3.next = 14;
206
247
  break;
207
248
 
208
249
  case 10:
209
- _context2.prev = 10;
210
- _context2.t0 = _context2["catch"](1);
250
+ _context3.prev = 10;
251
+ _context3.t0 = _context3["catch"](1);
211
252
  this.setState({
212
253
  canSubmit: true
213
254
  });
214
- return _context2.abrupt("return");
255
+ return _context3.abrupt("return");
215
256
 
216
257
  case 14:
217
258
  this.props.switchOffEditing();
@@ -220,10 +261,10 @@ var EntrySave = /*#__PURE__*/function (_Component) {
220
261
 
221
262
  case 17:
222
263
  case "end":
223
- return _context2.stop();
264
+ return _context3.stop();
224
265
  }
225
266
  }
226
- }, _callee2, this, [[1, 10]]);
267
+ }, _callee3, this, [[1, 10]]);
227
268
  }));
228
269
 
229
270
  function successfulSubmit() {
@@ -273,6 +314,7 @@ EntrySave.propTypes = {
273
314
  hideError: _propTypes.default.func.isRequired,
274
315
  initialFocusId: _propTypes.default.string,
275
316
  isValid: _propTypes.default.bool.isRequired,
317
+ itemEditArea: _propTypes.default.object,
276
318
  showError: _propTypes.default.func.isRequired,
277
319
  screenreaderNotification: _propTypes.default.func.isRequired,
278
320
  shouldValidateShareableContent: _propTypes.default.bool,
@@ -290,6 +332,7 @@ EntrySave.defaultProps = {
290
332
  disableSubmit: false,
291
333
  guid: null,
292
334
  initialFocusId: null,
335
+ itemEditArea: null,
293
336
  shouldValidateShareableContent: false
294
337
  };
295
338
  var _default = EntrySave;
@@ -67,7 +67,8 @@ var generateStyle = function generateStyle(componentTheme, props) {
67
67
  width: '100%'
68
68
  })),
69
69
  stimulusItem: {
70
- flex: '1 1 auto'
70
+ flex: '1 1 auto',
71
+ width: '100%'
71
72
  },
72
73
  stimulusGroup: (0, _objectSpread6.default)((0, _objectSpread6.default)({
73
74
  display: 'flex',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instructure/quiz-core",
3
- "version": "20.16.1-rc.8+80dd509d0",
3
+ "version": "20.17.0",
4
4
  "license": "MIT",
5
5
  "description": "The Quiz React SDK by Instructure Inc.",
6
6
  "author": "Instructure, Inc. Engineering and Product Design",
@@ -44,11 +44,11 @@
44
44
  "@instructure/emotion": "^8.51.0",
45
45
  "@instructure/grading-utils": "^1.0.0",
46
46
  "@instructure/outcomes-ui": "^3.2.2",
47
- "@instructure/quiz-common": "20.16.1-rc.8+80dd509d0",
48
- "@instructure/quiz-i18n": "20.16.1-rc.8+80dd509d0",
49
- "@instructure/quiz-interactions": "20.16.1-rc.8+80dd509d0",
50
- "@instructure/quiz-number-input": "20.16.1-rc.8+80dd509d0",
51
- "@instructure/quiz-rce": "20.16.1-rc.8+80dd509d0",
47
+ "@instructure/quiz-common": "^20.17.0",
48
+ "@instructure/quiz-i18n": "^20.17.0",
49
+ "@instructure/quiz-interactions": "^20.17.0",
50
+ "@instructure/quiz-number-input": "^20.17.0",
51
+ "@instructure/quiz-rce": "^20.17.0",
52
52
  "@instructure/ui-a11y-content": "^8.51.0",
53
53
  "@instructure/ui-alerts": "^8.51.0",
54
54
  "@instructure/ui-avatar": "^8.51.0",
@@ -93,8 +93,8 @@
93
93
  "@instructure/ui-themes": "^8.51.0",
94
94
  "@instructure/ui-toggle-details": "^8.51.0",
95
95
  "@instructure/ui-tooltip": "^8.51.0",
96
- "@instructure/ui-top-nav-bar": "^8.51.0",
97
- "@instructure/ui-tray": "^8.51.0",
96
+ "@instructure/ui-top-nav-bar": "^8.55.0",
97
+ "@instructure/ui-tray": "8.55.1",
98
98
  "@instructure/ui-truncate-text": "^8.51.0",
99
99
  "@instructure/ui-utils": "^8.51.0",
100
100
  "@instructure/ui-view": "^8.51.0",
@@ -111,7 +111,7 @@
111
111
  "file-saver": "~2.0.5",
112
112
  "humps": "^2.0.0",
113
113
  "immutable": "^3.8.1",
114
- "instructure-validations": "20.16.1-rc.8+80dd509d0",
114
+ "instructure-validations": "^20.17.0",
115
115
  "ipaddr.js": "^1.5.4",
116
116
  "isomorphic-fetch": "^2.2.0",
117
117
  "isuuid": "^0.1.0",
@@ -142,7 +142,7 @@
142
142
  "uuid": "^3.2.1"
143
143
  },
144
144
  "devDependencies": {
145
- "@instructure/quiz-scripts": "20.16.0",
145
+ "@instructure/quiz-scripts": "^20.17.0",
146
146
  "@instructure/ui-axe-check": "^8.51.0",
147
147
  "@instructure/ui-babel-preset": "^7.22.1",
148
148
  "@instructure/ui-karma-config": "^7.22.1",
@@ -163,7 +163,7 @@
163
163
  "jquery": "^2.2.3",
164
164
  "karma-junit-reporter": "^2.0.1",
165
165
  "most-subject": "^5.3.0",
166
- "quiz-presets": "20.16.1-rc.8+80dd509d0",
166
+ "quiz-presets": "^20.17.0",
167
167
  "react": "^16.8.6",
168
168
  "react-addons-test-utils": "^15.6.2",
169
169
  "react-dom": "^16.8.6",
@@ -179,5 +179,5 @@
179
179
  "publishConfig": {
180
180
  "access": "public"
181
181
  },
182
- "gitHead": "80dd509d088767c8d222f534bbf703a95c183760"
182
+ "gitHead": "7cfde18187bb7f81e74fc8471e3da12c596b176c"
183
183
  }