@pie-element/math-inline 12.1.1-next.15 → 12.1.1-next.29

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.
Files changed (101) hide show
  1. package/CHANGELOG.json +2627 -0
  2. package/CHANGELOG.md +2473 -0
  3. package/LICENSE.md +5 -0
  4. package/README.md +3 -0
  5. package/configure/CHANGELOG.json +1652 -0
  6. package/configure/CHANGELOG.md +2101 -0
  7. package/configure/lib/configure.js +186 -0
  8. package/configure/lib/configure.js.map +1 -0
  9. package/configure/lib/defaults.js +185 -0
  10. package/configure/lib/defaults.js.map +1 -0
  11. package/configure/lib/general-config-block.js +525 -0
  12. package/configure/lib/general-config-block.js.map +1 -0
  13. package/configure/lib/index.js +136 -0
  14. package/configure/lib/index.js.map +1 -0
  15. package/configure/lib/response.js +369 -0
  16. package/configure/lib/response.js.map +1 -0
  17. package/configure/lib/utils.js +31 -0
  18. package/configure/lib/utils.js.map +1 -0
  19. package/configure/package.json +29 -0
  20. package/controller/CHANGELOG.json +1002 -0
  21. package/controller/CHANGELOG.md +1536 -0
  22. package/controller/lib/defaults.js +43 -0
  23. package/controller/lib/defaults.js.map +1 -0
  24. package/controller/lib/index.js +383 -0
  25. package/controller/lib/index.js.map +1 -0
  26. package/controller/lib/utils.js +11 -0
  27. package/controller/lib/utils.js.map +1 -0
  28. package/controller/package.json +26 -0
  29. package/docs/config-schema.json +2071 -0
  30. package/docs/config-schema.json.md +1533 -0
  31. package/docs/demo/config.js +8 -0
  32. package/docs/demo/generate.js +41 -0
  33. package/docs/demo/index.html +1 -0
  34. package/docs/demo/session.js +11 -0
  35. package/docs/pie-schema.json +1472 -0
  36. package/docs/pie-schema.json.md +845 -0
  37. package/lib/index.js +93 -0
  38. package/lib/index.js.map +1 -0
  39. package/lib/main.js +1030 -0
  40. package/lib/main.js.map +1 -0
  41. package/lib/print.js +92 -0
  42. package/lib/print.js.map +1 -0
  43. package/lib/simple-question-block.js +148 -0
  44. package/lib/simple-question-block.js.map +1 -0
  45. package/lib/utils.js +11 -0
  46. package/lib/utils.js.map +1 -0
  47. package/package.json +26 -93
  48. package/configure.js +0 -2
  49. package/controller.js +0 -1
  50. package/dist/author/configure.d.ts +0 -25
  51. package/dist/author/configure.js +0 -114
  52. package/dist/author/defaults.d.ts +0 -186
  53. package/dist/author/defaults.js +0 -145
  54. package/dist/author/general-config-block.d.ts +0 -35
  55. package/dist/author/general-config-block.js +0 -390
  56. package/dist/author/index.d.ts +0 -60
  57. package/dist/author/index.js +0 -77
  58. package/dist/author/response.d.ts +0 -40
  59. package/dist/author/response.js +0 -238
  60. package/dist/author/utils.d.ts +0 -14
  61. package/dist/author/utils.js +0 -13
  62. package/dist/browser/author/index.js +0 -36149
  63. package/dist/browser/author/index.js.map +0 -1
  64. package/dist/browser/controller/index.js +0 -37789
  65. package/dist/browser/controller/index.js.map +0 -1
  66. package/dist/browser/delivery/index.js +0 -84
  67. package/dist/browser/delivery/index.js.map +0 -1
  68. package/dist/browser/dist-BTyrpsXL.js +0 -317
  69. package/dist/browser/dist-BTyrpsXL.js.map +0 -1
  70. package/dist/browser/dist-D9ARZhQk.js +0 -1426
  71. package/dist/browser/dist-D9ARZhQk.js.map +0 -1
  72. package/dist/browser/dist-gZPCFLwA.js +0 -19418
  73. package/dist/browser/dist-gZPCFLwA.js.map +0 -1
  74. package/dist/browser/main-DIAGtm9r.js +0 -973
  75. package/dist/browser/main-DIAGtm9r.js.map +0 -1
  76. package/dist/browser/math-inline.css +0 -2
  77. package/dist/browser/print/index.js +0 -50
  78. package/dist/browser/print/index.js.map +0 -1
  79. package/dist/controller/defaults.d.ts +0 -44
  80. package/dist/controller/defaults.js +0 -39
  81. package/dist/controller/index.d.ts +0 -22
  82. package/dist/controller/index.js +0 -171
  83. package/dist/controller/utils.d.ts +0 -12
  84. package/dist/controller/utils.js +0 -7
  85. package/dist/delivery/index.d.ts +0 -22
  86. package/dist/delivery/index.js +0 -55
  87. package/dist/delivery/main.d.ts +0 -44
  88. package/dist/delivery/main.js +0 -606
  89. package/dist/delivery/simple-question-block.d.ts +0 -27
  90. package/dist/delivery/simple-question-block.js +0 -94
  91. package/dist/delivery/utils.d.ts +0 -12
  92. package/dist/delivery/utils.js +0 -7
  93. package/dist/index.d.ts +0 -1
  94. package/dist/index.iife.d.ts +0 -8
  95. package/dist/index.iife.js +0 -227
  96. package/dist/index.js +0 -2
  97. package/dist/math-inline.css +0 -2
  98. package/dist/print/index.d.ts +0 -15
  99. package/dist/print/index.js +0 -50
  100. package/dist/runtime-support.d.ts +0 -12
  101. package/dist/runtime-support.js +0 -12
package/lib/main.js ADDED
@@ -0,0 +1,1030 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.default = exports.Main = void 0;
8
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
+ var _react = _interopRequireDefault(require("react"));
10
+ var _propTypes = _interopRequireDefault(require("prop-types"));
11
+ var _correctAnswerToggle = _interopRequireDefault(require("@pie-lib/correct-answer-toggle"));
12
+ var _mathInput = require("@pie-lib/math-input");
13
+ var _renderUi = require("@pie-lib/render-ui");
14
+ var _mathRendering = require("@pie-lib/math-rendering");
15
+ var _styles = require("@mui/material/styles");
16
+ var _Tooltip = _interopRequireDefault(require("@mui/material/Tooltip"));
17
+ var _utils = require("./utils");
18
+ var _lodashEs = require("lodash-es");
19
+ var _simpleQuestionBlock = _interopRequireDefault(require("./simple-question-block"));
20
+ var _translator = _interopRequireDefault(require("@pie-lib/translator"));
21
+ var _reactDom = _interopRequireDefault(require("react-dom"));
22
+ const {
23
+ translator
24
+ } = _translator.default;
25
+ let registered = false;
26
+ const NEWLINE_LATEX = /\\newline/g;
27
+ const REGEX = /{{response}}/gm;
28
+ const DEFAULT_KEYPAD_VARIANT = 6;
29
+
30
+ // !!! If you're using Chrome but have selected the "iPad" device in Chrome Developer Tools, the navigator.userAgent string may still report as
31
+ // Safari because Chrome on iOS actually uses the Safari rendering engine under the hood due to Apple's restrictions on third-party browser engines.
32
+ // When you select the "iPad" device in Chrome Developer Tools, you're essentially emulating the behavior of Safari on an iPad, including the user agent string.
33
+ // Therefore, even though you're using Chrome, the user agent string will resemble that of Safari on an iPad.
34
+ // Since the regular expression /^((?!chrome|android).)*safari/i checks for the presence of "safari" in the user agent string while excluding "chrome" and "android",
35
+ // it will return true in this case because "safari" is present in the user agent string emulated by Chrome when in iPad mode.
36
+ const IS_SAFARI = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
37
+ function generateAdditionalKeys(keyData = []) {
38
+ return keyData.map(key => ({
39
+ name: key,
40
+ latex: key,
41
+ write: key,
42
+ label: key
43
+ }));
44
+ }
45
+ function isChildOfCurrentPieElement(child, parent) {
46
+ let node = child;
47
+ while (node !== null) {
48
+ if (parent && node === parent) {
49
+ return true;
50
+ }
51
+ node = node.parentNode;
52
+ }
53
+ return false;
54
+ }
55
+ function getKeyPadWidth(additionalKeys = [], equationEditor) {
56
+ return Math.floor(additionalKeys.length / 5) * 30 + (equationEditor === 'miscellaneous' ? 600 : 500);
57
+ }
58
+ function prepareForStatic(model, state) {
59
+ const {
60
+ config,
61
+ disabled
62
+ } = model || {};
63
+ const {
64
+ expression,
65
+ responses,
66
+ printMode,
67
+ alwaysShowCorrect
68
+ } = config || {};
69
+ if (config && expression) {
70
+ const modelExpression = expression;
71
+ if (state.showCorrect) {
72
+ return responses && responses.length && responses[0].answer;
73
+ }
74
+ let answerBlocks = 1; // assume one at least
75
+ // build out local state model using responses declared in expression
76
+
77
+ return (modelExpression || '').replace(REGEX, function () {
78
+ const answer = state.session.answers[`r${answerBlocks}`];
79
+ if (printMode && !alwaysShowCorrect) {
80
+ const blankSpace = '\\ \\ '.repeat(30) + '\\newline ';
81
+ return `\\MathQuillMathField[r${answerBlocks++}]{${blankSpace.repeat(3)}}`;
82
+ }
83
+ if (disabled) {
84
+ return `\\embed{answerBlock}[r${answerBlocks++}]`;
85
+ }
86
+ return `\\MathQuillMathField[r${answerBlocks++}]{${answer && answer.value || ''}}`;
87
+ }).replace(NEWLINE_LATEX, '\\embed{newLine}[]');
88
+ }
89
+ }
90
+ function parseAnswers(session, model) {
91
+ const answers = {};
92
+ if (model.config && model.config.expression) {
93
+ let answerBlocks = 1; // assume one at least
94
+ // build out local state model using responses declared in expression
95
+
96
+ (model.config.expression || '').replace(REGEX, () => {
97
+ answers[`r${answerBlocks}`] = {
98
+ value: session && session.answers && session.answers[`r${answerBlocks}`] && session.answers[`r${answerBlocks}`].value || ''
99
+ };
100
+ answerBlocks += 1;
101
+ });
102
+ }
103
+ return answers;
104
+ }
105
+ class Main extends _react.default.Component {
106
+ constructor(props) {
107
+ super(props);
108
+ (0, _defineProperty2.default)(this, "handleAnswerBlockDomUpdate", () => {
109
+ const {
110
+ model
111
+ } = this.props;
112
+ const {
113
+ session,
114
+ showCorrect
115
+ } = this.state;
116
+ const answers = session.answers;
117
+ if (this.root && model.disabled && !showCorrect) {
118
+ Object.keys(answers).forEach(answerId => {
119
+ const el = this.root.querySelector(`#${answerId}`);
120
+ const indexEl = this.root.querySelector(`#${answerId}Index`);
121
+ // const correct = model.correctness && model.correctness.correct;
122
+
123
+ if (el) {
124
+ const answer = answers[answerId];
125
+ (0, _mathInput.applyStaticMath)(el, answer && answer.value || '');
126
+ if (!model.view) {
127
+ // for now, we're not going to be showing individual response correctness
128
+ // TODO re-attach the classes once we are
129
+ // el.parentElement.parentElement.classList.add(
130
+ // correct ? 'correct' : 'incorrect'
131
+ // );
132
+ } else {
133
+ el.parentElement.parentElement.classList.remove('correct');
134
+ el.parentElement.parentElement.classList.remove('incorrect');
135
+ }
136
+
137
+ // For now, we're not going to be indexing response blocks
138
+ // TODO go back to indexing once we support individual response correctness
139
+ // indexEl.textContent = `R${idx + 1}`;
140
+ indexEl.textContent = 'R';
141
+ }
142
+ });
143
+ }
144
+ (0, _mathRendering.renderMath)(this.root);
145
+ });
146
+ (0, _defineProperty2.default)(this, "updateAria", () => {
147
+ if (this.root) {
148
+ // Update aria-hidden for .mq-selectable elements
149
+ const selectableElements = this.root.querySelectorAll('.mq-selectable');
150
+ selectableElements.forEach(elem => elem.setAttribute('aria-hidden', 'true'));
151
+
152
+ // Update aria-label for textarea elements and add aria-describedby
153
+ const textareaElements = this.root.querySelectorAll('textarea');
154
+ textareaElements.forEach((elem, index) => {
155
+ elem.setAttribute('aria-label', 'Enter answer.');
156
+
157
+ // Create a unique id for each instructions element
158
+ const instructionsId = `instructions-${index}`;
159
+
160
+ // Find the parent element that contains the textarea
161
+ const parent = elem.closest('.mq-textarea');
162
+ if (parent) {
163
+ // Create or find the instructions element within the parent
164
+ let instructionsElement = parent.querySelector(`#${instructionsId}`);
165
+ if (!instructionsElement) {
166
+ instructionsElement = document.createElement('span');
167
+ instructionsElement.id = instructionsId;
168
+ instructionsElement.className = 'sr-only';
169
+ instructionsElement.textContent = 'This field supports both keypad and keyboard input. Use the keyboard to access and interact with the on-screen math keypad, which accepts LaTeX markup. Use the down arrow key to open the keypad and navigate its buttons. Use the escape key to close the keypad and return to the input field.';
170
+ parent.insertBefore(instructionsElement, elem);
171
+ }
172
+ elem.setAttribute('aria-describedby', instructionsId);
173
+ }
174
+ });
175
+ }
176
+ });
177
+ (0, _defineProperty2.default)(this, "focusFirstKeypadElement", () => {
178
+ setTimeout(() => {
179
+ const keypadElement = document.querySelector('[data-keypad]');
180
+ if (keypadElement) {
181
+ const firstButton = keypadElement.querySelector("button, [role='button']");
182
+ if (firstButton) {
183
+ firstButton.focus();
184
+ }
185
+ }
186
+ }, 0);
187
+ });
188
+ (0, _defineProperty2.default)(this, "handleKeyDown", (event, id) => {
189
+ const isTrigerredFromActualPieElement = isChildOfCurrentPieElement(event.target, this.root);
190
+ const isAnswerInputFocused = this.mqStatic && this.mqStatic.inputRef?.current ? this.mqStatic.inputRef?.current.contains(document.activeElement) : document.activeElement?.getAttribute('aria-label') === 'Enter answer.';
191
+ const {
192
+ key,
193
+ type
194
+ } = event;
195
+ const isClickOrTouchEvent = type === 'click' || type === 'touchstart';
196
+ if (isAnswerInputFocused && (key === 'ArrowDown' || isClickOrTouchEvent)) {
197
+ if (this.state.activeAnswerBlock !== id && isTrigerredFromActualPieElement) {
198
+ this.cleanupKeyDownListener();
199
+ this.setState({
200
+ activeAnswerBlock: id
201
+ }, () => {
202
+ this.onSubFieldFocus(id);
203
+ if (key === 'ArrowDown') {
204
+ this.focusFirstKeypadElement();
205
+ }
206
+ });
207
+ }
208
+ } else if (event.key === 'Escape') {
209
+ this.setState({
210
+ activeAnswerBlock: ''
211
+ });
212
+ }
213
+ });
214
+ (0, _defineProperty2.default)(this, "onSubFieldFocus", id => {
215
+ if (!this.handleEvent) {
216
+ this.handleEvent = event => {
217
+ this.handleKeyDown(event, id);
218
+ };
219
+ document.addEventListener('keydown', this.handleEvent);
220
+ document.addEventListener('click', this.handleEvent);
221
+ document.addEventListener('touchstart', this.handleEvent);
222
+ }
223
+ });
224
+ (0, _defineProperty2.default)(this, "cleanupKeyDownListener", () => {
225
+ if (this.handleEvent) {
226
+ document.removeEventListener('keydown', this.handleEvent);
227
+ document.removeEventListener('click', this.handleEvent);
228
+ document.removeEventListener('touchstart', this.handleEvent);
229
+ this.handleEvent = null;
230
+ }
231
+ });
232
+ (0, _defineProperty2.default)(this, "onDone", () => {});
233
+ (0, _defineProperty2.default)(this, "onSimpleResponseChange", response => {
234
+ this.setState(state => ({
235
+ session: {
236
+ ...state.session,
237
+ response
238
+ }
239
+ }), this.callOnSessionChange);
240
+ });
241
+ (0, _defineProperty2.default)(this, "toNodeData", data => {
242
+ if (!data) {
243
+ return;
244
+ }
245
+ const {
246
+ type,
247
+ value
248
+ } = data;
249
+ if (type === 'command' || type === 'cursor') {
250
+ return data;
251
+ } else if (type === 'answer') {
252
+ return {
253
+ type: 'answer',
254
+ ...data
255
+ };
256
+ } else if (value === 'clear') {
257
+ return {
258
+ type: 'clear'
259
+ };
260
+ } else {
261
+ return {
262
+ type: 'write',
263
+ value
264
+ };
265
+ }
266
+ });
267
+ (0, _defineProperty2.default)(this, "setInput", input => {
268
+ this.input = input;
269
+ });
270
+ (0, _defineProperty2.default)(this, "onClick", data => {
271
+ const scrollX = window.scrollX;
272
+ const scrollY = window.scrollY;
273
+ const c = this.toNodeData(data);
274
+ if (c.type === 'clear') {
275
+ this.input.clear();
276
+ } else if (c.type === 'command') {
277
+ if (Array.isArray(c.value)) {
278
+ c.value.forEach(vv => {
279
+ this.input.cmd(vv);
280
+ });
281
+ } else {
282
+ this.input.cmd(c.value);
283
+ }
284
+ } else if (c.type === 'cursor') {
285
+ this.input.keystroke(c.value);
286
+ } else {
287
+ this.input.write(c.value);
288
+ }
289
+ this.input.focus();
290
+ requestAnimationFrame(() => {
291
+ window.scrollTo(scrollX, scrollY);
292
+ requestAnimationFrame(() => window.scrollTo(scrollX, scrollY));
293
+ });
294
+ });
295
+ (0, _defineProperty2.default)(this, "callOnSessionChange", () => {
296
+ const {
297
+ onSessionChange
298
+ } = this.props;
299
+ if (onSessionChange) {
300
+ onSessionChange(this.state.session);
301
+ }
302
+ });
303
+ (0, _defineProperty2.default)(this, "toggleShowCorrect", show => {
304
+ this.setState({
305
+ showCorrect: show
306
+ }, this.handleAnswerBlockDomUpdate);
307
+ });
308
+ (0, _defineProperty2.default)(this, "subFieldChanged", (name, subfieldValue) => {
309
+ (0, _mathInput.updateSpans)();
310
+ if (name) {
311
+ const scrollX = window.scrollX;
312
+ const scrollY = window.scrollY;
313
+ this.setState(state => ({
314
+ session: {
315
+ ...state.session,
316
+ completeAnswer: this.mqStatic && this.mqStatic.mathField.latex(),
317
+ answers: {
318
+ ...state.session.answers,
319
+ [name]: {
320
+ value: subfieldValue
321
+ }
322
+ }
323
+ }
324
+ }), () => {
325
+ this.callOnSessionChange();
326
+ requestAnimationFrame(() => {
327
+ window.scrollTo(scrollX, scrollY);
328
+ });
329
+ });
330
+ }
331
+ });
332
+ (0, _defineProperty2.default)(this, "getFieldName", (changeField, fields) => {
333
+ const {
334
+ answers
335
+ } = this.state.session;
336
+ if (Object.keys(answers || {}).length) {
337
+ const keys = Object.keys(answers);
338
+ return keys.find(k => {
339
+ const tf = fields[k];
340
+ return tf && tf.id == changeField.id;
341
+ });
342
+ }
343
+ });
344
+ (0, _defineProperty2.default)(this, "onBlur", e => {
345
+ const {
346
+ relatedTarget,
347
+ currentTarget
348
+ } = e || {};
349
+
350
+ // our keypad is in tooltip
351
+ // in this way we see if event was triggered from the keypad
352
+ const isKeypadOpen = currentTarget && currentTarget.closest('[role=tooltip]');
353
+ function getParentWithRoleTooltip(element, depth = 0) {
354
+ // only run this max 16 times
355
+ if (!element || depth >= 16) return null;
356
+ const parent = element.offsetParent;
357
+ if (!parent) return null;
358
+ if (parent.getAttribute('role') === 'tooltip') {
359
+ return parent;
360
+ }
361
+ return getParentWithRoleTooltip(parent, depth + 1);
362
+ }
363
+ function getDeepChildDataKeypad(element, depth = 0) {
364
+ // only run this max 4 times
365
+ if (!element || depth >= 4) return null;
366
+ const child = element?.children?.[0];
367
+ if (!child) return null;
368
+ if (child.attributes && child.attributes['data-keypad']) {
369
+ return child;
370
+ }
371
+ return getDeepChildDataKeypad(child, depth + 1);
372
+ }
373
+ const parentWithTooltipRole = getParentWithRoleTooltip(relatedTarget);
374
+ const childWithDataKeypad = parentWithTooltipRole ? getDeepChildDataKeypad(parentWithTooltipRole) : null;
375
+ if (!relatedTarget || !currentTarget || !childWithDataKeypad?.attributes['data-keypad']) {
376
+ // if event was trigered from the keypad, avoid closing the keypad
377
+ if (!isKeypadOpen) {
378
+ this.setState({
379
+ activeAnswerBlock: ''
380
+ });
381
+ }
382
+ }
383
+ // else {
384
+ // // Just for debugging purpose:
385
+ // console.log('\n\nNew childWithDataKeypad', childWithDataKeypad);
386
+ //
387
+ // if (IS_SAFARI) {
388
+ // // (IS_SAFARI && !relatedTarget?.offsetParent?.children[0]?.children[0]?.attributes?.['data-keypad'])
389
+ // console.log('What was being used', relatedTarget?.offsetParent?.children[0]?.children[0]);
390
+ // } else {
391
+ // // (!IS_SAFARI && !relatedTarget?.offsetParent?.children[0]?.attributes?.['data-keypad']) ||
392
+ // console.log('What was being used', relatedTarget?.offsetParent?.children[0]);
393
+ // }
394
+ // }
395
+ });
396
+ const {
397
+ model: _model,
398
+ session: _session
399
+ } = props;
400
+ const _answers = parseAnswers(_session, _model);
401
+ this.state = {
402
+ session: {
403
+ ...props.session,
404
+ answers: _answers
405
+ },
406
+ activeAnswerBlock: '',
407
+ showCorrect: this.props.model.config.alwaysShowCorrect || false,
408
+ tooltipContainerRef: /*#__PURE__*/_react.default.createRef()
409
+ };
410
+ }
411
+ UNSAFE_componentWillMount() {
412
+ if (typeof window !== 'undefined') {
413
+ if (!registered) {
414
+ (0, _mathInput.registerEmbed)('answerBlock', data => {
415
+ const classNames = getBlockClassNames();
416
+ return {
417
+ htmlString: `<div class="${classNames.blockContainer}">
418
+ <div class="${classNames.blockResponse}" id="${data}Index">R</div>
419
+ <div class="${classNames.blockMath}">
420
+ <span id="${data}"></span>
421
+ </div>
422
+ </div>`,
423
+ text: () => 'text',
424
+ latex: () => `\\embed{answerBlock}[${data}]`
425
+ };
426
+ });
427
+ registered = true;
428
+ }
429
+ }
430
+ }
431
+ countResponseOccurrences(expression) {
432
+ const pattern = /\{\{response\}\}/g;
433
+ const matches = expression?.match(pattern);
434
+ return matches ? matches.length : 0;
435
+ }
436
+ UNSAFE_componentWillReceiveProps(nextProps) {
437
+ const {
438
+ config
439
+ } = this.props.model;
440
+ const {
441
+ config: nextConfig = {}
442
+ } = nextProps.model || {};
443
+ const {
444
+ session
445
+ } = this.props;
446
+ const {
447
+ session: nextSession = {}
448
+ } = nextProps || {};
449
+
450
+ // in case session props changed in parent, we need to catch this and update local state
451
+ // example: when env is changing in pieoneer
452
+ if (session && nextSession && !(0, _lodashEs.isEqual)(session.answers, nextSession.answers)) {
453
+ this.setState({
454
+ session: {
455
+ ...nextSession,
456
+ answers: parseAnswers(nextSession, this.props.model)
457
+ }
458
+ });
459
+ }
460
+
461
+ // check if the note is the default one for prev language and change to the default one for new language
462
+ // this check is necessary in order to diferanciate between default and authour defined note
463
+ // and only change between languages for default ones
464
+ if (config.note && config.language && config.language !== nextConfig.language && config.note === translator.t('mathInline.primaryCorrectWithAlternates', {
465
+ lng: config.language
466
+ })) {
467
+ config.note = translator.t('mathInline.primaryCorrectWithAlternates', {
468
+ lng: nextConfig.language
469
+ });
470
+ }
471
+ if (config.env && config.env.mode !== 'evaluate' || nextConfig.env && nextConfig.env.mode !== 'evaluate') {
472
+ this.setState({
473
+ ...this.state.session,
474
+ showCorrect: false
475
+ });
476
+ }
477
+ if (nextConfig.alwaysShowCorrect) {
478
+ this.setState({
479
+ showCorrect: true
480
+ });
481
+ }
482
+ if (this.countResponseOccurrences(config.expression) < this.countResponseOccurrences(nextConfig.expression)) {
483
+ setTimeout(() => this.updateAria(), 100);
484
+ }
485
+ if (config && config.responses && config.responses.length !== nextConfig.responses.length || !config && nextConfig && nextConfig.responses || config && nextConfig && config.expression !== nextConfig.expression) {
486
+ const newAnswers = {};
487
+ const answers = this.state.session.answers;
488
+ let answerBlocks = 1; // assume one at least
489
+
490
+ // build out local state model using responses declared in expression
491
+ (nextConfig.expression || '').replace(REGEX, () => {
492
+ newAnswers[`r${answerBlocks}`] = {
493
+ value: answers && answers[`r${answerBlocks}`] && answers[`r${answerBlocks}`].value || ''
494
+ };
495
+ answerBlocks++;
496
+ });
497
+ this.setState(state => ({
498
+ session: {
499
+ ...state.session,
500
+ completeAnswer: this.mqStatic && this.mqStatic.mathField.latex(),
501
+ answers: newAnswers
502
+ }
503
+ }), this.handleAnswerBlockDomUpdate);
504
+ }
505
+ }
506
+ shouldComponentUpdate(nextProps, nextState) {
507
+ const sameModel = (0, _lodashEs.isEqual)(this.props.model, nextProps.model);
508
+ const sameState = (0, _lodashEs.isEqual)(this.state, nextState);
509
+ return !sameModel || !sameState;
510
+ }
511
+ componentDidMount() {
512
+ this.handleAnswerBlockDomUpdate();
513
+ this.updateAria();
514
+ setTimeout(() => (0, _mathRendering.renderMath)(this.root), 100);
515
+ }
516
+ componentDidUpdate(prevProps, prevState) {
517
+ this.handleAnswerBlockDomUpdate();
518
+ const prevResponseType = prevProps.model?.config?.responseType;
519
+ const currentResponseType = this.props.model?.config?.responseType;
520
+ if (prevResponseType !== currentResponseType) {
521
+ this.updateAria();
522
+ }
523
+ }
524
+ componentWillUnmount() {
525
+ if (this.cleanupKeyDownListener) {
526
+ this.cleanupKeyDownListener();
527
+ }
528
+ }
529
+ setTooltipRef(ref) {
530
+ // Safari Hack: https://stackoverflow.com/a/42764495/5757635
531
+ setTimeout(() => {
532
+ if (ref && IS_SAFARI) {
533
+ const div = document.querySelector("[role='tooltip']");
534
+ if (div) {
535
+ const el = div.firstChild;
536
+ el.setAttribute('tabindex', '-1');
537
+ }
538
+ }
539
+ }, 1);
540
+ }
541
+ render() {
542
+ const {
543
+ model
544
+ } = this.props;
545
+ const {
546
+ activeAnswerBlock,
547
+ showCorrect,
548
+ session,
549
+ tooltipContainerRef
550
+ } = this.state;
551
+ const {
552
+ config,
553
+ correctness,
554
+ disabled,
555
+ extraCSSRules,
556
+ view,
557
+ teacherInstructions,
558
+ rationale,
559
+ feedback,
560
+ animationsDisabled,
561
+ printMode,
562
+ alwaysShowCorrect,
563
+ language
564
+ } = model || {};
565
+ if (!config) {
566
+ return null;
567
+ }
568
+ const {
569
+ showNote,
570
+ note,
571
+ prompt,
572
+ responses,
573
+ responseType,
574
+ equationEditor,
575
+ customKeys,
576
+ id,
577
+ env: {
578
+ mode,
579
+ role
580
+ } = {}
581
+ } = config || {};
582
+ const displayNote = (showCorrect || mode === 'view' && role === 'instructor') && showNote && note;
583
+ const emptyResponse = (0, _lodashEs.isEmpty)(responses);
584
+ const showCorrectAnswerToggle = !emptyResponse && correctness && correctness.correctness !== 'correct';
585
+ const tooltipModeEnabled = disabled && correctness;
586
+ const additionalKeys = generateAdditionalKeys(customKeys);
587
+ const correct = correctness && correctness.correct;
588
+ const staticLatex = prepareForStatic(model, this.state) || '';
589
+ const viewMode = disabled && !correctness;
590
+ const studentPrintMode = printMode && !alwaysShowCorrect;
591
+ const showRationale = rationale && ((0, _renderUi.hasText)(rationale) || (0, _renderUi.hasMedia)(rationale));
592
+ const showTeacherInstructions = teacherInstructions && ((0, _renderUi.hasText)(teacherInstructions) || (0, _renderUi.hasMedia)(teacherInstructions));
593
+ const printView = /*#__PURE__*/_react.default.createElement(PrintContainer, null, /*#__PURE__*/_react.default.createElement(_mathInput.mq.Static, {
594
+ className: "static-math",
595
+ ref: mqStatic => {
596
+ if (mqStatic) this.mqStatic = mqStatic;
597
+ },
598
+ latex: staticLatex,
599
+ onSubFieldChange: this.subFieldChanged,
600
+ getFieldName: this.getFieldName,
601
+ setInput: this.setInput,
602
+ onSubFieldFocus: this.onSubFieldFocus,
603
+ onBlur: this.onBlur
604
+ }));
605
+ const midContent = /*#__PURE__*/_react.default.createElement(MainContent, null, mode === 'gather' && /*#__PURE__*/_react.default.createElement(SrOnly, null, "Math Equation Response Question"), viewMode && showTeacherInstructions && (!animationsDisabled ? /*#__PURE__*/_react.default.createElement(StyledCollapsible, {
606
+ labels: {
607
+ hidden: 'Show Teacher Instructions',
608
+ visible: 'Hide Teacher Instructions'
609
+ }
610
+ }, /*#__PURE__*/_react.default.createElement("div", {
611
+ dangerouslySetInnerHTML: {
612
+ __html: teacherInstructions
613
+ }
614
+ })) : /*#__PURE__*/_react.default.createElement("div", {
615
+ dangerouslySetInnerHTML: {
616
+ __html: teacherInstructions
617
+ }
618
+ })), prompt && /*#__PURE__*/_react.default.createElement(PromptContainer, null, /*#__PURE__*/_react.default.createElement(_renderUi.PreviewPrompt, {
619
+ prompt: prompt
620
+ })), studentPrintMode ? printView : /*#__PURE__*/_react.default.createElement(_renderUi.Readable, {
621
+ false: true
622
+ }, /*#__PURE__*/_react.default.createElement(InputAndKeypadContainer, {
623
+ tabIndex: 0
624
+ }, responseType === _utils.ResponseTypes.simple && /*#__PURE__*/_react.default.createElement(_simpleQuestionBlock.default, {
625
+ onSimpleResponseChange: this.onSimpleResponseChange,
626
+ showCorrect: showCorrect,
627
+ emptyResponse: emptyResponse,
628
+ model: model,
629
+ session: session,
630
+ onSubFieldFocus: this.onSubFieldFocus,
631
+ showKeypad: !!activeAnswerBlock
632
+ }), responseType === _utils.ResponseTypes.advanced && /*#__PURE__*/_react.default.createElement(Expression, {
633
+ ref: tooltipContainerRef,
634
+ isIncorrect: !emptyResponse && !correct && !showCorrect,
635
+ isCorrect: !emptyResponse && (correct || showCorrect),
636
+ showCorrectness: !emptyResponse && disabled && correctness && !view,
637
+ correctAnswerShown: showCorrect,
638
+ printCorrect: printMode && alwaysShowCorrect
639
+ }, /*#__PURE__*/_react.default.createElement(_Tooltip.default, {
640
+ ref: ref => this.setTooltipRef(ref),
641
+ enterTouchDelay: 0,
642
+ interactive: true,
643
+ open: !!activeAnswerBlock,
644
+ slotProps: {
645
+ popper: {
646
+ container: tooltipContainerRef?.current || undefined,
647
+ placement: 'bottom-start',
648
+ sx: {
649
+ backgroundColor: 'transparent',
650
+ width: '650px',
651
+ opacity: 1,
652
+ '& .MuiTooltip-arrow': {
653
+ display: 'none'
654
+ }
655
+ },
656
+ modifiers: [{
657
+ name: 'offset',
658
+ options: {
659
+ offset: [0, 8]
660
+ }
661
+ }, {
662
+ name: 'preventOverflow',
663
+ enabled: true,
664
+ options: {
665
+ boundary: 'viewport',
666
+ padding: 8
667
+ }
668
+ }, {
669
+ name: 'computeStyles',
670
+ options: {
671
+ adaptive: true,
672
+ gpuAcceleration: true
673
+ }
674
+ }, {
675
+ name: 'flip',
676
+ enabled: false
677
+ }]
678
+ },
679
+ tooltip: {
680
+ sx: {
681
+ fontSize: 'initial',
682
+ backgroundColor: 'transparent',
683
+ width: '600px',
684
+ marginTop: 0,
685
+ paddingTop: 0,
686
+ boxShadow: 'none'
687
+ }
688
+ }
689
+ },
690
+ title: Object.keys(session.answers).map(answerId => answerId === activeAnswerBlock && !(showCorrect || disabled) && /*#__PURE__*/_react.default.createElement(ResponseContainer, {
691
+ "data-keypad": true,
692
+ key: answerId,
693
+ style: {
694
+ // marginTop: this.mqStatic && this.mqStatic.input.offsetHeight - 20,
695
+ width: getKeyPadWidth(additionalKeys, equationEditor)
696
+ }
697
+ }, /*#__PURE__*/_react.default.createElement(_mathInput.HorizontalKeypad, {
698
+ additionalKeys: additionalKeys,
699
+ mode: equationEditor || DEFAULT_KEYPAD_VARIANT,
700
+ onClick: this.onClick
701
+ })) || null)
702
+ }, /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(_mathInput.mq.Static, {
703
+ className: "static-math",
704
+ ref: mqStatic => {
705
+ if (mqStatic) this.mqStatic = mqStatic;
706
+ },
707
+ latex: staticLatex,
708
+ onSubFieldChange: this.subFieldChanged,
709
+ getFieldName: this.getFieldName,
710
+ setInput: this.setInput,
711
+ onSubFieldFocus: this.onSubFieldFocus,
712
+ onBlur: this.onBlur
713
+ })))))), viewMode && displayNote && /*#__PURE__*/_react.default.createElement(Note, {
714
+ dangerouslySetInnerHTML: {
715
+ __html: `<strong>Note:</strong> ${note}`
716
+ }
717
+ }), viewMode && showRationale && (!animationsDisabled ? /*#__PURE__*/_react.default.createElement(_renderUi.Collapsible, {
718
+ labels: {
719
+ hidden: 'Show Rationale',
720
+ visible: 'Hide Rationale'
721
+ }
722
+ }, /*#__PURE__*/_react.default.createElement("div", {
723
+ dangerouslySetInnerHTML: {
724
+ __html: rationale
725
+ }
726
+ })) : /*#__PURE__*/_react.default.createElement("div", {
727
+ dangerouslySetInnerHTML: {
728
+ __html: rationale
729
+ }
730
+ })));
731
+ if (tooltipModeEnabled && (showCorrectAnswerToggle || showTeacherInstructions || showRationale || feedback)) {
732
+ return /*#__PURE__*/_react.default.createElement(StyledUiLayout, {
733
+ extraCSSRules: extraCSSRules,
734
+ ref: r => {
735
+ // eslint-disable-next-line react/no-find-dom-node
736
+ const domNode = _reactDom.default.findDOMNode(r);
737
+ this.root = domNode || this.root;
738
+ }
739
+ }, /*#__PURE__*/_react.default.createElement(StyledTooltip, {
740
+ interactive: true,
741
+ enterTouchDelay: 0,
742
+ placement: "bottom-start",
743
+ slotProps: {
744
+ tooltip: {
745
+ sx: theme => ({
746
+ background: `${_renderUi.color.primaryLight()} !important`,
747
+ color: _renderUi.color.text(),
748
+ padding: theme.spacing(2),
749
+ border: `1px solid ${_renderUi.color.secondary()}`,
750
+ fontSize: '16px',
751
+ '& :not(.MathJax) > table tr': {
752
+ '&:nth-child(2n)': {
753
+ backgroundColor: 'unset !important'
754
+ }
755
+ }
756
+ })
757
+ },
758
+ popper: {
759
+ sx: {
760
+ opacity: 1
761
+ },
762
+ modifiers: [{
763
+ name: 'offset',
764
+ options: {
765
+ offset: [0, 2]
766
+ }
767
+ }]
768
+ }
769
+ },
770
+ title: /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(MainContent, null, showCorrectAnswerToggle && /*#__PURE__*/_react.default.createElement(StyledCorrectAnswerToggle, {
771
+ language: language,
772
+ show: true,
773
+ toggled: showCorrect,
774
+ onToggle: this.toggleShowCorrect
775
+ })), showTeacherInstructions && /*#__PURE__*/_react.default.createElement(StyledCollapsible, {
776
+ key: "collapsible-teacher-instructions",
777
+ labels: {
778
+ hidden: 'Show Teacher Instructions',
779
+ visible: 'Hide Teacher Instructions'
780
+ }
781
+ }, /*#__PURE__*/_react.default.createElement(_renderUi.PreviewPrompt, {
782
+ prompt: teacherInstructions
783
+ })), displayNote && (0, _renderUi.hasText)(note) && /*#__PURE__*/_react.default.createElement(StyledCollapsible, {
784
+ key: "collapsible-note",
785
+ labels: {
786
+ hidden: translator.t('common:showNote', {
787
+ lng: language
788
+ }),
789
+ visible: translator.t('common:hideNote', {
790
+ lng: language
791
+ })
792
+ }
793
+ }, /*#__PURE__*/_react.default.createElement(_renderUi.PreviewPrompt, {
794
+ prompt: note
795
+ })), showRationale && /*#__PURE__*/_react.default.createElement(StyledCollapsible, {
796
+ key: "collapsible-rationale",
797
+ labels: {
798
+ hidden: 'Show Rationale',
799
+ visible: 'Hide Rationale'
800
+ }
801
+ }, /*#__PURE__*/_react.default.createElement(_renderUi.PreviewPrompt, {
802
+ prompt: rationale
803
+ })), feedback && /*#__PURE__*/_react.default.createElement(_renderUi.Feedback, {
804
+ correctness: correctness.correctness,
805
+ feedback: feedback
806
+ }))
807
+ }, midContent));
808
+ }
809
+ return /*#__PURE__*/_react.default.createElement(StyledUiLayout, {
810
+ id: id,
811
+ extraCSSRules: extraCSSRules,
812
+ ref: r => {
813
+ // eslint-disable-next-line react/no-find-dom-node
814
+ const domNode = _reactDom.default.findDOMNode(r);
815
+ this.root = domNode || this.root;
816
+ }
817
+ }, midContent);
818
+ }
819
+ }
820
+
821
+ // Helper function to get class names for HTML string generation
822
+ exports.Main = Main;
823
+ (0, _defineProperty2.default)(Main, "propTypes", {
824
+ session: _propTypes.default.object.isRequired,
825
+ onSessionChange: _propTypes.default.func,
826
+ model: _propTypes.default.object.isRequired
827
+ });
828
+ const getBlockClassNames = () => {
829
+ return {
830
+ blockContainer: 'block-container',
831
+ blockResponse: 'block-response',
832
+ blockMath: 'block-math'
833
+ };
834
+ };
835
+
836
+ // CSS for block classes used in HTML string generation
837
+ if (typeof document !== 'undefined') {
838
+ const styleId = 'math-inline-block-styles';
839
+ if (!document.getElementById(styleId)) {
840
+ const style = document.createElement('style');
841
+ style.id = styleId;
842
+ style.textContent = `
843
+ .block-container {
844
+ margin: 8px !important;
845
+ display: inline-flex;
846
+ border: 2px solid grey !important;
847
+ }
848
+ .block-response {
849
+ color: grey;
850
+ background: #f5f5f5;
851
+ font-size: 0.8rem !important;
852
+ padding: 4px !important;
853
+ display: flex;
854
+ align-items: center;
855
+ justify-content: center;
856
+ border-right: 2px solid #bdbdbd !important;
857
+ flex-shrink: 0;
858
+ flex-grow: 0;
859
+ flex-basis: auto;
860
+ }
861
+ .block-math {
862
+ color: ${_renderUi.color.text()};
863
+ background-color: ${_renderUi.color.background()};
864
+ padding: 4px !important;
865
+ display: flex;
866
+ align-items: center;
867
+ justify-content: center;
868
+ flex-grow: 1;
869
+ }
870
+ .block-math > .mq-math-mode > .mq-hasCursor > .mq-cursor {
871
+ display: none;
872
+ }
873
+ .sr-only {
874
+ position: absolute;
875
+ left: -10000px;
876
+ top: auto;
877
+ width: 1px;
878
+ height: 1px;
879
+ overflow: hidden;
880
+ }
881
+ .static-math > .mq-root-block > .mq-editable-field {
882
+ border-color: ${_renderUi.color.text()};
883
+ }
884
+ `;
885
+ document.head.appendChild(style);
886
+ }
887
+ }
888
+ const StyledUiLayout = (0, _styles.styled)(_renderUi.UiLayout)(() => ({
889
+ color: _renderUi.color.text(),
890
+ backgroundColor: _renderUi.color.background(),
891
+ display: 'inline-block'
892
+ }));
893
+ const StyledTooltip = (0, _styles.styled)(_Tooltip.default)({
894
+ // Styles applied via slotProps.sx below
895
+ });
896
+ const PromptContainer = (0, _styles.styled)('div')(({
897
+ theme
898
+ }) => ({
899
+ marginBottom: theme.spacing(2)
900
+ }));
901
+ const MainContent = (0, _styles.styled)('div')({
902
+ width: '100%',
903
+ position: 'relative',
904
+ backgroundColor: _renderUi.color.background(),
905
+ color: _renderUi.color.text()
906
+ });
907
+ const Note = (0, _styles.styled)('div')(({
908
+ theme
909
+ }) => ({
910
+ paddingBottom: theme.spacing(2)
911
+ }));
912
+ const StyledCollapsible = (0, _styles.styled)(_renderUi.Collapsible)(({
913
+ theme
914
+ }) => ({
915
+ marginBottom: theme.spacing(2)
916
+ }));
917
+ const ResponseContainer = (0, _styles.styled)('div')(({
918
+ theme
919
+ }) => ({
920
+ zIndex: 10,
921
+ minWidth: '400px',
922
+ marginTop: theme.spacing(2)
923
+ }));
924
+ const Expression = (0, _styles.styled)('div', {
925
+ shouldForwardProp: prop => !['isIncorrect', 'isCorrect', 'showCorrectness', 'correctAnswerShown', 'printCorrect'].includes(prop)
926
+ })(({
927
+ theme,
928
+ isIncorrect,
929
+ isCorrect,
930
+ showCorrectness,
931
+ correctAnswerShown,
932
+ printCorrect
933
+ }) => {
934
+ const borderColor = isIncorrect ? _renderUi.color.incorrect() : isCorrect ? _renderUi.color.correct() : undefined;
935
+ return {
936
+ maxWidth: 'fit-content',
937
+ padding: theme.spacing(0.25),
938
+ ...(showCorrectness && {
939
+ border: borderColor ? `2px solid ${borderColor} !important` : '2px solid'
940
+ }),
941
+ ...(!showCorrectness && borderColor && {
942
+ borderColor: `${borderColor} !important`
943
+ }),
944
+ ...(correctAnswerShown && {
945
+ padding: theme.spacing(1),
946
+ letterSpacing: '0.5px'
947
+ }),
948
+ ...(printCorrect && {
949
+ border: `2px solid ${_renderUi.color.correct()} !important`
950
+ }),
951
+ '& .mq-math-mode': {
952
+ '& .mq-root-block': {
953
+ paddingRight: '0 !important',
954
+ paddingLeft: '0 !important',
955
+ '& .mq-editable-field': {
956
+ minWidth: '10px',
957
+ padding: theme.spacing(0.4)
958
+ }
959
+ },
960
+ '& sup': {
961
+ top: 0
962
+ }
963
+ }
964
+ };
965
+ });
966
+ const InputAndKeypadContainer = (0, _styles.styled)('div')({
967
+ position: 'relative',
968
+ '& .mq-overarrow-inner': {
969
+ border: 'none !important',
970
+ padding: '0 !important'
971
+ },
972
+ '& .mq-overarrow-inner-right': {
973
+ display: 'none !important'
974
+ },
975
+ '& .mq-overarrow-inner-left': {
976
+ display: 'none !important'
977
+ },
978
+ '& .mq-overarrow.mq-arrow-both': {
979
+ minWidth: '1.23em',
980
+ '& *': {
981
+ lineHeight: '1 !important'
982
+ },
983
+ '&:before': {
984
+ top: '-0.4em',
985
+ left: '-1px'
986
+ },
987
+ '&:after': {
988
+ top: '-2.4em',
989
+ right: '-1px'
990
+ },
991
+ '&.mq-empty:after': {
992
+ top: '-0.45em'
993
+ }
994
+ },
995
+ '& .mq-overarrow.mq-arrow-right': {
996
+ '&:before': {
997
+ top: '-0.4em',
998
+ right: '-1px'
999
+ }
1000
+ },
1001
+ '& .mq-longdiv-inner': {
1002
+ borderTop: '1px solid !important',
1003
+ paddingTop: '1.5px !important'
1004
+ },
1005
+ '& .mq-parallelogram': {
1006
+ lineHeight: 0.85
1007
+ }
1008
+ });
1009
+ const PrintContainer = (0, _styles.styled)('div')(({
1010
+ theme
1011
+ }) => ({
1012
+ marginBottom: theme.spacing(1),
1013
+ pointerEvents: 'none'
1014
+ }));
1015
+ const SrOnly = (0, _styles.styled)('h2')({
1016
+ position: 'absolute',
1017
+ left: '-10000px',
1018
+ top: 'auto',
1019
+ width: '1px',
1020
+ height: '1px',
1021
+ overflow: 'hidden'
1022
+ });
1023
+ const StyledCorrectAnswerToggle = (0, _styles.styled)(_correctAnswerToggle.default)(({
1024
+ theme
1025
+ }) => ({
1026
+ color: _renderUi.color.text(),
1027
+ marginBottom: theme.spacing(2)
1028
+ }));
1029
+ var _default = exports.default = Main;
1030
+ //# sourceMappingURL=main.js.map