@khanacademy/perseus 6.2.2 → 6.3.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/dist/index.js CHANGED
@@ -10,7 +10,6 @@ var classNames = require('classnames');
10
10
  var React = require('react');
11
11
  var _ = require('underscore');
12
12
  var $ = require('jquery');
13
- var MathQuill = require('mathquill');
14
13
  var ReactDOM = require('react-dom');
15
14
  var PropTypes = require('prop-types');
16
15
  var kmath = require('@khanacademy/kmath');
@@ -59,7 +58,6 @@ var classNames__default = /*#__PURE__*/_interopDefaultLegacy(classNames);
59
58
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
60
59
  var ___default = /*#__PURE__*/_interopDefaultLegacy(_);
61
60
  var $__default = /*#__PURE__*/_interopDefaultLegacy($);
62
- var MathQuill__default = /*#__PURE__*/_interopDefaultLegacy(MathQuill);
63
61
  var ReactDOM__default = /*#__PURE__*/_interopDefaultLegacy(ReactDOM);
64
62
  var ReactDOM__namespace = /*#__PURE__*/_interopNamespace(ReactDOM);
65
63
  var PropTypes__default = /*#__PURE__*/_interopDefaultLegacy(PropTypes);
@@ -209,10 +207,10 @@ const symbStyle = {
209
207
  const basic = [() => [/*#__PURE__*/React__namespace.createElement("span", {
210
208
  key: "plus",
211
209
  style: slightlyBig
212
- }, "+"), "PLUS"], () => [/*#__PURE__*/React__namespace.createElement("span", {
210
+ }, "+"), "PLUS", i18n__namespace._("Plus")], () => [/*#__PURE__*/React__namespace.createElement("span", {
213
211
  key: "minus",
214
212
  style: prettyBig
215
- }, "-"), "MINUS"],
213
+ }, "-"), "MINUS", i18n__namespace._("Minus")],
216
214
  // TODO(joel) - display as \cdot when appropriate
217
215
  props => {
218
216
  const {
@@ -222,12 +220,12 @@ props => {
222
220
  return [/*#__PURE__*/React__namespace.createElement(TeX, {
223
221
  key: "times",
224
222
  style: prettyBig
225
- }, i18n__namespace.doNotTranslate("\\times")), "TIMES"];
223
+ }, i18n__namespace.doNotTranslate("\\times")), "TIMES", i18n__namespace._("Multiply")];
226
224
  }
227
225
  return [/*#__PURE__*/React__namespace.createElement(TeX, {
228
226
  key: "times",
229
227
  style: prettyBig
230
- }, i18n__namespace.doNotTranslate("\\cdot")), "CDOT"];
228
+ }, i18n__namespace.doNotTranslate("\\cdot")), "CDOT", i18n__namespace._("Multiply")];
231
229
  }, () => {
232
230
  const {
233
231
  TeX
@@ -235,7 +233,7 @@ props => {
235
233
  return [/*#__PURE__*/React__namespace.createElement(TeX, {
236
234
  key: "frac",
237
235
  style: prettyBig
238
- }, i18n__namespace.doNotTranslate("\\frac{x}{y}")), "FRAC"];
236
+ }, i18n__namespace.doNotTranslate("\\frac{x}{y}")), "FRAC", i18n__namespace._("Fraction, excluding the current expression")];
239
237
  }];
240
238
  const buttonSets = {
241
239
  basic,
@@ -245,7 +243,7 @@ const buttonSets = {
245
243
  } = getDependencies();
246
244
  return [/*#__PURE__*/React__namespace.createElement(TeX, {
247
245
  key: "div"
248
- }, i18n__namespace.doNotTranslate("\\div")), "DIVIDE"];
246
+ }, i18n__namespace.doNotTranslate("\\div")), "DIVIDE", i18n__namespace._("Divide")];
249
247
  }]),
250
248
  trig: [() => {
251
249
  const {
@@ -253,21 +251,21 @@ const buttonSets = {
253
251
  } = getDependencies();
254
252
  return [/*#__PURE__*/React__namespace.createElement(TeX, {
255
253
  key: "sin"
256
- }, i18n__namespace.doNotTranslate("\\sin")), "SIN"];
254
+ }, i18n__namespace.doNotTranslate("\\sin")), "SIN", i18n__namespace._("Sine")];
257
255
  }, () => {
258
256
  const {
259
257
  TeX
260
258
  } = getDependencies();
261
259
  return [/*#__PURE__*/React__namespace.createElement(TeX, {
262
260
  key: "cos"
263
- }, i18n__namespace.doNotTranslate("\\cos")), "COS"];
261
+ }, i18n__namespace.doNotTranslate("\\cos")), "COS", i18n__namespace._("Cosine")];
264
262
  }, () => {
265
263
  const {
266
264
  TeX
267
265
  } = getDependencies();
268
266
  return [/*#__PURE__*/React__namespace.createElement(TeX, {
269
267
  key: "tan"
270
- }, i18n__namespace.doNotTranslate("\\tan")), "TAN"];
268
+ }, i18n__namespace.doNotTranslate("\\tan")), "TAN", i18n__namespace._("Tangent")];
271
269
  }, () => {
272
270
  const {
273
271
  TeX
@@ -275,7 +273,7 @@ const buttonSets = {
275
273
  return [/*#__PURE__*/React__namespace.createElement(TeX, {
276
274
  key: "theta",
277
275
  style: symbStyle
278
- }, i18n__namespace.doNotTranslate("\\theta")), "THETA"];
276
+ }, i18n__namespace.doNotTranslate("\\theta")), "THETA", i18n__namespace._("Theta")];
279
277
  }, () => {
280
278
  const {
281
279
  TeX
@@ -287,7 +285,7 @@ const buttonSets = {
287
285
  }, i18n__namespace.doNotTranslate("phi")), /*#__PURE__*/React__namespace.createElement(TeX, {
288
286
  key: "pi",
289
287
  style: symbStyle
290
- }, i18n__namespace.doNotTranslate("\\phi"))), "PHI"];
288
+ }, i18n__namespace.doNotTranslate("\\phi"))), "PHI", i18n__namespace._("Phi")];
291
289
  }],
292
290
  prealgebra: [() => {
293
291
  const {
@@ -295,7 +293,7 @@ const buttonSets = {
295
293
  } = getDependencies();
296
294
  return [/*#__PURE__*/React__namespace.createElement(TeX, {
297
295
  key: "sqrt"
298
- }, i18n__namespace.doNotTranslate("\\sqrt{x}")), "SQRT"];
296
+ }, i18n__namespace.doNotTranslate("\\sqrt{x}")), "SQRT", i18n__namespace._("Square root")];
299
297
  },
300
298
  // TODO(joel) - how does desmos do this?
301
299
  () => {
@@ -304,7 +302,7 @@ const buttonSets = {
304
302
  } = getDependencies();
305
303
  return [/*#__PURE__*/React__namespace.createElement(TeX, {
306
304
  key: "nthroot"
307
- }, i18n__namespace.doNotTranslate("\\sqrt[3]{x}")), "NTHROOT3"];
305
+ }, i18n__namespace.doNotTranslate("\\sqrt[3]{x}")), "NTHROOT3", i18n__namespace._("Cube root")];
308
306
  }, () => {
309
307
  const {
310
308
  TeX
@@ -312,7 +310,7 @@ const buttonSets = {
312
310
  return [/*#__PURE__*/React__namespace.createElement(TeX, {
313
311
  key: "pow",
314
312
  style: slightlyBig
315
- }, i18n__namespace.doNotTranslate("a^b")), "POW"];
313
+ }, i18n__namespace.doNotTranslate("a^b")), "POW", i18n__namespace._("Exponent")];
316
314
  }, () => {
317
315
  const {
318
316
  TeX
@@ -320,7 +318,7 @@ const buttonSets = {
320
318
  return [/*#__PURE__*/React__namespace.createElement(TeX, {
321
319
  key: "pi",
322
320
  style: slightlyBig
323
- }, i18n__namespace.doNotTranslate("\\pi")), "PI"];
321
+ }, i18n__namespace.doNotTranslate("\\pi")), "PI", i18n__namespace._("Pi")];
324
322
  }],
325
323
  logarithms: [() => {
326
324
  const {
@@ -328,21 +326,21 @@ const buttonSets = {
328
326
  } = getDependencies();
329
327
  return [/*#__PURE__*/React__namespace.createElement(TeX, {
330
328
  key: "log"
331
- }, i18n__namespace.doNotTranslate("\\log")), "LOG"];
329
+ }, i18n__namespace.doNotTranslate("\\log")), "LOG", i18n__namespace._("Logarithm with base 10")];
332
330
  }, () => {
333
331
  const {
334
332
  TeX
335
333
  } = getDependencies();
336
334
  return [/*#__PURE__*/React__namespace.createElement(TeX, {
337
335
  key: "ln"
338
- }, i18n__namespace.doNotTranslate("\\ln")), "LN"];
336
+ }, i18n__namespace.doNotTranslate("\\ln")), "LN", i18n__namespace._("Natural logarithm")];
339
337
  }, () => {
340
338
  const {
341
339
  TeX
342
340
  } = getDependencies();
343
341
  return [/*#__PURE__*/React__namespace.createElement(TeX, {
344
342
  key: "log_b"
345
- }, i18n__namespace.doNotTranslate("\\log_b")), "LOG_B"];
343
+ }, i18n__namespace.doNotTranslate("\\log_b")), "LOG_B", i18n__namespace._("Logarithm with custom base")];
346
344
  }],
347
345
  "basic relations": [() => {
348
346
  const {
@@ -350,21 +348,21 @@ const buttonSets = {
350
348
  } = getDependencies();
351
349
  return [/*#__PURE__*/React__namespace.createElement(TeX, {
352
350
  key: "eq"
353
- }, "="), "EQUAL"];
351
+ }, "="), "EQUAL", i18n__namespace._("Equals sign")];
354
352
  }, () => {
355
353
  const {
356
354
  TeX
357
355
  } = getDependencies();
358
356
  return [/*#__PURE__*/React__namespace.createElement(TeX, {
359
357
  key: "lt"
360
- }, i18n__namespace.doNotTranslate("\\lt")), "LT"];
358
+ }, i18n__namespace.doNotTranslate("\\lt")), "LT", i18n__namespace._("Less than sign")];
361
359
  }, () => {
362
360
  const {
363
361
  TeX
364
362
  } = getDependencies();
365
363
  return [/*#__PURE__*/React__namespace.createElement(TeX, {
366
364
  key: "gt"
367
- }, i18n__namespace.doNotTranslate("\\gt")), "GT"];
365
+ }, i18n__namespace.doNotTranslate("\\gt")), "GT", i18n__namespace._("Greater than sign")];
368
366
  }],
369
367
  "advanced relations": [() => {
370
368
  const {
@@ -372,21 +370,21 @@ const buttonSets = {
372
370
  } = getDependencies();
373
371
  return [/*#__PURE__*/React__namespace.createElement(TeX, {
374
372
  key: "neq"
375
- }, i18n__namespace.doNotTranslate("\\neq")), "NEQ"];
373
+ }, i18n__namespace.doNotTranslate("\\neq")), "NEQ", i18n__namespace._("Not-equals sign")];
376
374
  }, () => {
377
375
  const {
378
376
  TeX
379
377
  } = getDependencies();
380
378
  return [/*#__PURE__*/React__namespace.createElement(TeX, {
381
379
  key: "leq"
382
- }, i18n__namespace.doNotTranslate("\\leq")), "LEQ"];
380
+ }, i18n__namespace.doNotTranslate("\\leq")), "LEQ", i18n__namespace._("Less than or equal to sign")];
383
381
  }, () => {
384
382
  const {
385
383
  TeX
386
384
  } = getDependencies();
387
385
  return [/*#__PURE__*/React__namespace.createElement(TeX, {
388
386
  key: "geq"
389
- }, i18n__namespace.doNotTranslate("\\geq")), "GEQ"];
387
+ }, i18n__namespace.doNotTranslate("\\geq")), "GEQ", i18n__namespace._("Greater than or equal to sign")];
390
388
  }]
391
389
  };
392
390
  const buttonSetsPropType = PropTypes__default["default"].arrayOf(PropTypes__default["default"].oneOf(___default["default"](buttonSets).keys()));
@@ -408,7 +406,8 @@ class TexButtons extends React__namespace.Component {
408
406
  // @ts-expect-error [FEI-5003] - TS2533 - Object is possibly 'null' or 'undefined'. | TS2339 - Property 'key' does not exist on type 'boolean | ReactChild | ReactFragment | ReactPortal'.
409
407
  ,
410
408
  key: symbol[0].key,
411
- type: "button"
409
+ type: "button",
410
+ "aria-label": symbol[2]
412
411
  }, symbol[0]);
413
412
  }));
414
413
  const buttonPopup = ___default["default"](buttonRows).map((row, i) => {
@@ -444,6 +443,8 @@ class MathInput extends React__namespace.Component {
444
443
  constructor() {
445
444
  super(...arguments);
446
445
  _defineProperty(this, "mouseDown", void 0);
446
+ _defineProperty(this, "__mathFieldWrapperRef", null);
447
+ _defineProperty(this, "__mathField", null);
447
448
  _defineProperty(this, "state", {
448
449
  focused: false
449
450
  });
@@ -498,12 +499,11 @@ class MathInput extends React__namespace.Component {
498
499
  return this.state.focused;
499
500
  });
500
501
  _defineProperty(this, "insert", value => {
501
- // @ts-expect-error [FEI-5003] - TS2554 - Expected 1 arguments, but got 0.
502
502
  const input = this.mathField();
503
503
  const inputModifier = customKeyTranslator[value];
504
504
  if (inputModifier) {
505
505
  inputModifier(input, value);
506
- input.focus();
506
+ input === null || input === void 0 ? void 0 : input.focus();
507
507
  return;
508
508
  }
509
509
 
@@ -514,131 +514,99 @@ class MathInput extends React__namespace.Component {
514
514
  if (___default["default"](value).isFunction()) {
515
515
  value(input);
516
516
  } else if (value[0] === "\\") {
517
- input.cmd(value).focus();
517
+ input === null || input === void 0 ? void 0 : input.cmd(value).focus();
518
518
  } else {
519
- input.write(value).focus();
519
+ input === null || input === void 0 ? void 0 : input.write(value).focus();
520
+ }
521
+ input === null || input === void 0 ? void 0 : input.focus();
522
+ });
523
+ _defineProperty(this, "mathField", () => {
524
+ if (!this.__mathField && this.__mathFieldWrapperRef) {
525
+ // Initialize MathQuill.MathField instance
526
+ this.__mathField = mathInput.createMathField(this.__mathFieldWrapperRef, baseConfig => ({
527
+ ...baseConfig,
528
+ handlers: {
529
+ edit: mathField => {
530
+ // This handler is guaranteed to be called on change, but
531
+ // unlike React it sometimes generates false positives.
532
+ // One of these is on initialization (with an empty string
533
+ // value), so we have to guard against that below.
534
+ let value = mathField.latex();
535
+
536
+ // Provide a MathQuill-compatible way to generate the
537
+ // not-equals sign without pasting unicode or typing TeX
538
+ value = value.replace(/<>/g, "\\ne");
539
+
540
+ // Use the specified symbol to represent multiplication
541
+ // TODO(alex): Add an option to disallow variables, in
542
+ // which case 'x' should get converted to '\\times'
543
+ if (this.props.convertDotToTimes) {
544
+ value = value.replace(/\\cdot/g, "\\times");
545
+
546
+ // Preserve cursor position in the common case:
547
+ // typing '*' to insert a multiplication sign.
548
+ // We do this by modifying internal MathQuill state
549
+ // directly, instead of waiting for `.latex()` to be
550
+ // called in `componentDidUpdate()`.
551
+ const left = mathField.__controller.cursor[mathInput.mathQuillInstance.L];
552
+ if (left && left.ctrlSeq === "\\cdot ") {
553
+ mathField.__controller.backspace();
554
+ mathField.cmd("\\times");
555
+ }
556
+ } else {
557
+ value = value.replace(/\\times/g, "\\cdot");
558
+ }
559
+ if (this.props.value !== value) {
560
+ this.props.onChange(value);
561
+ }
562
+ },
563
+ enter: () => {
564
+ // NOTE(kevinb): This isn't how answers to exercises are
565
+ // submitted. The actual mechanism for this can be found
566
+ // in exercise-problem-template.jsx, see `handleSubmit`.
567
+
568
+ // This handler is called when the user presses the enter
569
+ // key. Since this isn't an actual <input> element, we have
570
+ // to manually trigger the usually automatic form submit.
571
+ if (this.__mathFieldWrapperRef) {
572
+ $__default["default"](this.__mathFieldWrapperRef).submit();
573
+ }
574
+ },
575
+ upOutOf: mathField => {
576
+ // This handler is called when the user presses the up
577
+ // arrow key, but there is nowhere in the expression to go
578
+ // up to (no numerator or exponent). For ease of use,
579
+ // interpret this as an attempt to create an exponent.
580
+ mathField.typedText("^");
581
+ }
582
+ }
583
+ }));
520
584
  }
521
- input.focus();
522
- });
523
- _defineProperty(this, "mathField", options => {
524
- // The MathQuill API is now "versioned" through its own "InterVer"
525
- // system.
526
- // See: https://github.com/mathquill/mathquill/pull/459
527
- const MQ = MathQuill__default["default"].getInterface(2);
528
-
529
- // MathQuill.MathField takes a DOM node, MathQuill-ifies it if it's
530
- // seeing that node for the first time, then returns the associated
531
- // MathQuill object for that node. It is stable - will always return
532
- // the same object when called on the same DOM node.
533
- // eslint-disable-next-line react/no-string-refs
534
- return MQ.MathField(ReactDOM__default["default"].findDOMNode(this.refs.mathinput), options);
585
+ return this.__mathField;
535
586
  });
536
587
  _defineProperty(this, "focus", () => {
537
- // @ts-expect-error [FEI-5003] - TS2554 - Expected 1 arguments, but got 0.
538
- this.mathField().focus();
588
+ var _this$mathField;
589
+ (_this$mathField = this.mathField()) === null || _this$mathField === void 0 ? void 0 : _this$mathField.focus();
539
590
  this.setState({
540
591
  focused: true
541
592
  });
542
593
  });
543
594
  _defineProperty(this, "blur", () => {
544
- // @ts-expect-error [FEI-5003] - TS2554 - Expected 1 arguments, but got 0.
545
- this.mathField().blur();
595
+ var _this$mathField2;
596
+ (_this$mathField2 = this.mathField()) === null || _this$mathField2 === void 0 ? void 0 : _this$mathField2.blur();
546
597
  this.setState({
547
598
  focused: false
548
599
  });
549
600
  });
550
601
  }
551
602
  componentDidMount() {
603
+ var _this$mathField3;
552
604
  window.addEventListener("mousedown", this.handleMouseDown);
553
605
  window.addEventListener("mouseup", this.handleMouseUp);
554
- let initialized = false;
555
-
556
- // Initialize MathQuill.MathField instance
557
- this.mathField({
558
- // LaTeX commands that, when typed, are immediately replaced by the
559
- // appropriate symbol. This does not include ln, log, or any of the
560
- // trig functions; those are always interpreted as commands.
561
- autoCommands: "pi theta phi sqrt nthroot",
562
- // Pop the cursor out of super/subscripts on arithmetic operators
563
- // or (in)equalities.
564
- charsThatBreakOutOfSupSub: "+-*/=<>≠≤≥",
565
- // Prevent excessive super/subscripts or fractions from being
566
- // created without operands, e.g. when somebody holds down a key
567
- supSubsRequireOperand: true,
568
- // The name of this option is somewhat misleading, as tabbing in
569
- // MathQuill breaks you out of a nested context (fraction/script)
570
- // if you're in one, but moves focus to the next input if you're
571
- // not. Spaces (with this option enabled) are just ignored in the
572
- // latter case.
573
- //
574
- // TODO(alex): In order to allow inputting mixed numbers, we will
575
- // have to accept spaces in certain cases. The desired behavior is
576
- // still to escape nested contexts if currently in one, but to
577
- // insert a space if not (we don't expect mixed numbers in nested
578
- // contexts). We should also limit to one consecutive space.
579
- spaceBehavesLikeTab: true,
580
- handlers: {
581
- edited: mathField => {
582
- // This handler is guaranteed to be called on change, but
583
- // unlike React it sometimes generates false positives.
584
- // One of these is on initialization (with an empty string
585
- // value), so we have to guard against that below.
586
- let value = mathField.latex();
587
-
588
- // Provide a MathQuill-compatible way to generate the
589
- // not-equals sign without pasting unicode or typing TeX
590
- value = value.replace(/<>/g, "\\ne");
591
-
592
- // Use the specified symbol to represent multiplication
593
- // TODO(alex): Add an option to disallow variables, in
594
- // which case 'x' should get converted to '\\times'
595
- if (this.props.convertDotToTimes) {
596
- value = value.replace(/\\cdot/g, "\\times");
597
-
598
- // Preserve cursor position in the common case:
599
- // typing '*' to insert a multiplication sign.
600
- // We do this by modifying internal MathQuill state
601
- // directly, instead of waiting for `.latex()` to be
602
- // called in `componentDidUpdate()`.
603
- const left = mathField.__controller.cursor[MathQuill__default["default"].L];
604
- if (left && left.ctrlSeq === "\\cdot ") {
605
- mathField.__controller.backspace();
606
- mathField.cmd("\\times");
607
- }
608
- } else {
609
- value = value.replace(/\\times/g, "\\cdot");
610
- }
611
- if (initialized && this.props.value !== value) {
612
- this.props.onChange(value);
613
- }
614
- },
615
- enter: () => {
616
- // NOTE(kevinb): This isn't how answers to exercises are
617
- // submitted. The actual mechanism for this can be found
618
- // in exercise-problem-template.jsx, see `handleSubmit`.
619
-
620
- // This handler is called when the user presses the enter
621
- // key. Since this isn't an actual <input> element, we have
622
- // to manually trigger the usually automatic form submit.
623
- // eslint-disable-next-line react/no-string-refs
624
- // @ts-expect-error [FEI-5003] - TS2769 - No overload matches this call. | TS2339 - Property 'submit' does not exist on type 'JQueryStatic'.
625
- $__default["default"](ReactDOM__default["default"].findDOMNode(this.refs.mathinput)).submit();
626
- },
627
- upOutOf: mathField => {
628
- // This handler is called when the user presses the up
629
- // arrow key, but there is nowhere in the expression to go
630
- // up to (no numerator or exponent). For ease of use,
631
- // interpret this as an attempt to create an exponent.
632
- mathField.typedText("^");
633
- }
634
- }
635
- });
636
606
 
637
607
  // Ideally, we would be able to pass an initial value directly into
638
- // the constructor above
639
- // @ts-expect-error [FEI-5003] - TS2554 - Expected 1 arguments, but got 0.
640
- this.mathField().latex(this.props.value);
641
- initialized = true;
608
+ // the constructor
609
+ (_this$mathField3 = this.mathField()) === null || _this$mathField3 === void 0 ? void 0 : _this$mathField3.latex(this.props.value);
642
610
  }
643
611
  componentWillUnmount() {
644
612
  window.removeEventListener("mousedown", this.handleMouseDown);
@@ -681,10 +649,8 @@ class MathInput extends React__namespace.Component {
681
649
  display: "inline-block"
682
650
  }
683
651
  }, /*#__PURE__*/React__namespace.createElement("span", {
684
- className: className
685
- // eslint-disable-next-line react/no-string-refs
686
- ,
687
- ref: "mathinput",
652
+ className: className,
653
+ ref: ref => this.__mathFieldWrapperRef = ref,
688
654
  "aria-label": this.props.labelText,
689
655
  onFocus: this.handleFocus,
690
656
  onBlur: this.handleBlur