@khanacademy/math-input 4.1.0 → 4.2.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.
Files changed (77) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/components/input/math-wrapper.d.ts +1 -1
  3. package/dist/components/input/math-wrapper.js.flow +1 -1
  4. package/dist/components/input/mathquill-instance.d.ts +14 -3
  5. package/dist/components/input/mathquill-instance.js.flow +18 -3
  6. package/dist/components/input/mathquill-types.d.ts +28 -6
  7. package/dist/components/input/mathquill-types.js.flow +31 -7
  8. package/dist/components/key-handlers/handle-arrow.d.ts +3 -0
  9. package/dist/components/{input/key-handlers → key-handlers}/handle-arrow.js.flow +2 -2
  10. package/dist/components/{input/key-handlers → key-handlers}/handle-backspace.d.ts +1 -1
  11. package/dist/components/{input/key-handlers → key-handlers}/handle-backspace.js.flow +1 -1
  12. package/dist/components/key-handlers/handle-exponent.d.ts +3 -0
  13. package/dist/components/{input/key-handlers → key-handlers}/handle-exponent.js.flow +2 -2
  14. package/dist/components/{input/key-handlers → key-handlers}/handle-jump-out.d.ts +2 -2
  15. package/dist/components/{input/key-handlers → key-handlers}/handle-jump-out.js.flow +2 -2
  16. package/dist/components/key-handlers/key-translator.d.ts +4 -0
  17. package/dist/components/{key-translator.js.flow → key-handlers/key-translator.js.flow} +3 -3
  18. package/dist/components/keypad/geometry-page/index.d.ts +2 -1
  19. package/dist/components/keypad/geometry-page/index.js.flow +2 -1
  20. package/dist/components/keypad/index.d.ts +2 -1
  21. package/dist/components/keypad/index.js.flow +2 -1
  22. package/dist/components/keypad/keypad-page-items.d.ts +8 -16
  23. package/dist/components/keypad/keypad-page-items.js.flow +11 -16
  24. package/dist/components/keypad/numbers-page/index.d.ts +2 -1
  25. package/dist/components/keypad/numbers-page/index.js.flow +2 -1
  26. package/dist/components/keypad/operators-page/advanced-relations-buttons.d.ts +2 -1
  27. package/dist/components/keypad/operators-page/advanced-relations-buttons.js.flow +2 -1
  28. package/dist/components/keypad/operators-page/basic-relations-buttons.d.ts +2 -1
  29. package/dist/components/keypad/operators-page/basic-relations-buttons.js.flow +2 -1
  30. package/dist/components/keypad/operators-page/index.d.ts +2 -1
  31. package/dist/components/keypad/operators-page/index.js.flow +2 -1
  32. package/dist/components/keypad/operators-page/logarithms-buttons.d.ts +2 -1
  33. package/dist/components/keypad/operators-page/logarithms-buttons.js.flow +2 -1
  34. package/dist/components/keypad/operators-page/pre-algebra-buttons.d.ts +2 -1
  35. package/dist/components/keypad/operators-page/pre-algebra-buttons.js.flow +2 -1
  36. package/dist/es/index.js +395 -366
  37. package/dist/es/index.js.map +1 -1
  38. package/dist/index.d.ts +3 -1
  39. package/dist/index.js +398 -367
  40. package/dist/index.js.flow +6 -1
  41. package/dist/index.js.map +1 -1
  42. package/dist/types.d.ts +1 -0
  43. package/dist/types.js.flow +1 -0
  44. package/package.json +1 -1
  45. package/src/components/input/math-input.tsx +10 -14
  46. package/src/components/input/math-wrapper.ts +23 -49
  47. package/src/components/input/mathquill-helpers.ts +11 -11
  48. package/src/components/input/mathquill-instance.ts +57 -2
  49. package/src/components/input/mathquill-types.ts +37 -7
  50. package/src/components/{input/key-handlers → key-handlers}/handle-arrow.ts +6 -6
  51. package/src/components/{input/key-handlers → key-handlers}/handle-backspace.ts +19 -17
  52. package/src/components/{input/key-handlers → key-handlers}/handle-exponent.ts +8 -5
  53. package/src/components/{input/key-handlers → key-handlers}/handle-jump-out.ts +15 -10
  54. package/src/components/{key-translator.ts → key-handlers/key-translator.ts} +43 -28
  55. package/src/components/keypad/__tests__/Button.test.tsx +51 -0
  56. package/src/components/keypad/__tests__/keypad-button.test.tsx +41 -0
  57. package/src/components/keypad/__tests__/keypad-v2-mathquill.test.tsx +231 -0
  58. package/src/components/keypad/__tests__/keypad-v2.cypress.ts +46 -0
  59. package/src/components/keypad/geometry-page/index.tsx +2 -1
  60. package/src/components/keypad/index.tsx +2 -1
  61. package/src/components/keypad/keypad-mathquill.stories.tsx +15 -23
  62. package/src/components/keypad/keypad-page-items.tsx +10 -19
  63. package/src/components/keypad/numbers-page/index.tsx +2 -1
  64. package/src/components/keypad/operators-page/advanced-relations-buttons.tsx +2 -1
  65. package/src/components/keypad/operators-page/basic-relations-buttons.tsx +2 -1
  66. package/src/components/keypad/operators-page/index.tsx +2 -1
  67. package/src/components/keypad/operators-page/logarithms-buttons.tsx +2 -1
  68. package/src/components/keypad/operators-page/pre-algebra-buttons.tsx +2 -1
  69. package/src/index.ts +6 -1
  70. package/src/types.ts +2 -0
  71. package/tsconfig-build.json +1 -2
  72. package/tsconfig-build.tsbuildinfo +1 -1
  73. package/dist/components/input/__tests__/test-math-wrapper.d.ts +0 -8
  74. package/dist/components/input/__tests__/test-math-wrapper.js.flow +0 -14
  75. package/dist/components/input/key-handlers/handle-arrow.d.ts +0 -3
  76. package/dist/components/input/key-handlers/handle-exponent.d.ts +0 -3
  77. package/dist/components/key-translator.d.ts +0 -4
package/dist/es/index.js CHANGED
@@ -341,273 +341,52 @@ class DragListener {
341
341
  }
342
342
  }
343
343
 
344
- /**
345
- * Constants that are shared between multiple files.
346
- */
347
-
348
- let KeypadType = /*#__PURE__*/function (KeypadType) {
349
- KeypadType["FRACTION"] = "FRACTION";
350
- KeypadType["EXPRESSION"] = "EXPRESSION";
351
- return KeypadType;
352
- }({});
353
- const KeyTypes = ["EMPTY",
354
- // For numerals, variables, and any other characters that themselves
355
- // compose 'values'.
356
- "VALUE",
357
- // For buttons that insert or adjust math in an input.
358
- "OPERATOR",
359
- // For buttons that move the cursor in an input (including via
360
- // deletion).
361
- "INPUT_NAVIGATION",
362
- // For buttons that modify the broader keypad state (e.g., by changing
363
- // the visible pane).
364
- "KEYPAD_NAVIGATION",
365
- // For buttons that house multiple buttons and have no action
366
- // themselves.
367
- "MANY",
368
- // For the echo animation that appears on press.
369
- "ECHO"];
370
- let DeviceOrientation = /*#__PURE__*/function (DeviceOrientation) {
371
- DeviceOrientation["LANDSCAPE"] = "LANDSCAPE";
372
- DeviceOrientation["PORTRAIT"] = "PORTRAIT";
373
- return DeviceOrientation;
374
- }({});
375
- let DeviceType = /*#__PURE__*/function (DeviceType) {
376
- DeviceType["PHONE"] = "PHONE";
377
- DeviceType["TABLET"] = "TABLET";
378
- return DeviceType;
379
- }({});
380
- let LayoutMode = /*#__PURE__*/function (LayoutMode) {
381
- LayoutMode["FULLSCREEN"] = "FULLSCREEN";
382
- LayoutMode["COMPACT"] = "COMPACT";
383
- return LayoutMode;
384
- }({});
385
- let BorderDirection = /*#__PURE__*/function (BorderDirection) {
386
- BorderDirection["LEFT"] = "LEFT";
387
- BorderDirection["BOTTOM"] = "BOTTOM";
388
- return BorderDirection;
389
- }({});
390
- const BorderStyles = {
391
- LEFT: [BorderDirection.LEFT],
392
- BOTTOM: [BorderDirection.BOTTOM],
393
- ALL: [BorderDirection.LEFT, BorderDirection.BOTTOM],
394
- NONE: []
395
- };
396
- let IconType = /*#__PURE__*/function (IconType) {
397
- IconType["MATH"] = "MATH";
398
- IconType["SVG"] = "SVG";
399
- IconType["TEXT"] = "TEXT";
400
- return IconType;
401
- }({});
402
- let DecimalSeparator = /*#__PURE__*/function (DecimalSeparator) {
403
- DecimalSeparator["COMMA"] = "COMMA";
404
- DecimalSeparator["PERIOD"] = "PERIOD";
405
- return DecimalSeparator;
406
- }({});
407
- let EchoAnimationType = /*#__PURE__*/function (EchoAnimationType) {
408
- EchoAnimationType["SLIDE_AND_FADE"] = "SLIDE_AND_FADE";
409
- EchoAnimationType["FADE_ONLY"] = "FADE_ONLY";
410
- EchoAnimationType["LONG_FADE_ONLY"] = "LONG_FADE_ONLY";
411
- return EchoAnimationType;
412
- }({});
413
-
414
- // NOTES(kevinb):
415
- // - In order to get the correct decimal separator for the current locale,
416
- // the locale must bet set using `setLocale(kaLocale)` which can be
417
- // imported from wonder-blocks-i18n.
418
- // - Some languages/locales use different decimal separators than the ones
419
- // listed here. Much of the Arab world uses U+066C.
420
- const decimalSeparator = getDecimalSeparator() === "," ? DecimalSeparator.COMMA : DecimalSeparator.PERIOD;
421
-
422
- var MQ = MathQuill.getInterface(2);
423
-
424
- var ActionType = /*#__PURE__*/function (ActionType) {
425
- ActionType["WRITE"] = "write";
426
- ActionType["CMD"] = "cmd";
427
- ActionType["KEYSTROKE"] = "keystroke";
428
- ActionType[ActionType["MQ_END"] = 0] = "MQ_END";
429
- return ActionType;
430
- }(ActionType || {});
431
- const decimalSymbol = decimalSeparator === DecimalSeparator.COMMA ? "," : ".";
432
- function buildGenericCallback(str, type = ActionType.WRITE) {
433
- return function (mathQuill) {
434
- switch (type) {
435
- case ActionType.WRITE:
436
- {
437
- mathQuill.write(str);
438
- return;
439
- }
440
- case ActionType.CMD:
441
- {
442
- mathQuill.cmd(str);
443
- return;
444
- }
445
- case ActionType.KEYSTROKE:
446
- {
447
- mathQuill.keystroke(str);
448
- return;
449
- }
450
- }
344
+ // We only need one MathQuill instance (referred to as MQ in the docs)
345
+ // and that contains some MQ constants and the MathField constructor
346
+ const mathQuillInstance = MathQuill.getInterface(2);
347
+ function createBaseConfig() {
348
+ return {
349
+ // LaTeX commands that, when typed, are immediately replaced by the
350
+ // appropriate symbol. This does not include ln, log, or any of the
351
+ // trig functions; those are always interpreted as commands.
352
+ autoCommands: "pi theta phi sqrt nthroot",
353
+ // Pop the cursor out of super/subscripts on arithmetic operators
354
+ // or (in)equalities.
355
+ charsThatBreakOutOfSupSub: "+-*/=<>≠≤≥",
356
+ // Prevent excessive super/subscripts or fractions from being
357
+ // created without operands, e.g. when somebody holds down a key
358
+ supSubsRequireOperand: true,
359
+ // The name of this option is somewhat misleading, as tabbing in
360
+ // MathQuill breaks you out of a nested context (fraction/script)
361
+ // if you're in one, but moves focus to the next input if you're
362
+ // not. Spaces (with this option enabled) are just ignored in the
363
+ // latter case.
364
+ //
365
+ // TODO(alex): In order to allow inputting mixed numbers, we will
366
+ // have to accept spaces in certain cases. The desired behavior is
367
+ // still to escape nested contexts if currently in one, but to
368
+ // insert a space if not (we don't expect mixed numbers in nested
369
+ // contexts). We should also limit to one consecutive space.
370
+ spaceBehavesLikeTab: true
451
371
  };
452
372
  }
453
- const keyToMathquillMap = {
454
- CDOT: buildGenericCallback("\\cdot"),
455
- COS: buildGenericCallback("cos"),
456
- DECIMAL: buildGenericCallback(decimalSymbol),
457
- DIVIDE: buildGenericCallback("\\div"),
458
- EQUAL: buildGenericCallback("="),
459
- EXP: buildGenericCallback("^"),
460
- EXP_2: buildGenericCallback("^2"),
461
- EXP_3: buildGenericCallback("^3"),
462
- GEQ: buildGenericCallback("\\geq"),
463
- GT: buildGenericCallback(">"),
464
- LEQ: buildGenericCallback("\\leq"),
465
- LN: buildGenericCallback("\\ln"),
466
- LOG: buildGenericCallback("\\log"),
467
- LT: buildGenericCallback("<"),
468
- MINUS: buildGenericCallback("-"),
469
- NEGATIVE: buildGenericCallback("-"),
470
- NEQ: buildGenericCallback("\\neq"),
471
- PERCENT: buildGenericCallback("%"),
472
- PERIOD: buildGenericCallback("."),
473
- PLUS: buildGenericCallback("+"),
474
- SIN: buildGenericCallback("sin"),
475
- TAN: buildGenericCallback("tan"),
476
- TIMES: buildGenericCallback("\\times"),
477
- // The `FRAC_EXCLUSIVE` variant is handled manually, since we may need to do
478
- // some additional navigation depending on the cursor position.
479
- FRAC_INCLUSIVE: buildGenericCallback("/", ActionType.CMD),
480
- LEFT_PAREN: buildGenericCallback("(", ActionType.CMD),
481
- RIGHT_PAREN: buildGenericCallback(")", ActionType.CMD),
482
- SQRT: buildGenericCallback("sqrt", ActionType.CMD),
483
- PHI: buildGenericCallback("\\phi", ActionType.CMD),
484
- PI: buildGenericCallback("pi", ActionType.CMD),
485
- THETA: buildGenericCallback("theta", ActionType.CMD),
486
- RADICAL: buildGenericCallback("nthroot", ActionType.CMD),
487
- UP: buildGenericCallback("Up", ActionType.KEYSTROKE),
488
- DOWN: buildGenericCallback("Down", ActionType.KEYSTROKE),
489
- CUBE_ROOT: mathQuill => {
490
- mathQuill.write("\\sqrt[3]{}");
491
- mathQuill.keystroke("Left"); // under the root
492
- },
493
-
494
- FRAC_EXCLUSIVE: mathQuill => {
495
- const cursor = mathQuill.__controller.cursor;
496
- // If there's nothing to the left of the cursor, then we want to
497
- // leave the cursor to the left of the fraction after creating it.
498
- const shouldNavigateLeft = cursor[MQ.L] === ActionType.MQ_END;
499
- mathQuill.cmd("\\frac");
500
- if (shouldNavigateLeft) {
501
- mathQuill.keystroke("Left");
502
- }
503
- },
504
- LOG_B: mathQuill => {
505
- mathQuill.typedText("log_");
506
- mathQuill.keystroke("Right");
507
- mathQuill.typedText("(");
508
- mathQuill.keystroke("Left");
509
- mathQuill.keystroke("Left");
510
- },
511
- LOG_N: mathQuill => {
512
- mathQuill.write("log_{ }\\left(\\right)");
513
- mathQuill.keystroke("Left"); // into parentheses
514
- mathQuill.keystroke("Left"); // out of parentheses
515
- mathQuill.keystroke("Left"); // into index
516
- },
517
-
518
- NTHROOT3: mathQuill => {
519
- mathQuill.typedText("nthroot3");
520
- mathQuill.keystroke("Right");
521
- },
522
- POW: mathQuill => {
523
- const contents = mathQuill.latex();
524
- mathQuill.typedText("^");
525
373
 
526
- // If the input hasn't changed (for example, if we're
527
- // attempting to add an exponent on an empty input or an empty
528
- // denominator), insert our own "a^b"
529
- if (mathQuill.latex() === contents) {
530
- mathQuill.typedText("a^b");
531
- }
532
- },
533
- // These need to be overwritten by the consumer
534
- // if they're going to be used
535
- FRAC: () => {},
536
- RIGHT: () => {},
537
- LEFT: () => {},
538
- BACKSPACE: () => {},
539
- DISMISS: () => {},
540
- JUMP_OUT_PARENTHESES: () => {},
541
- JUMP_OUT_EXPONENT: () => {},
542
- JUMP_OUT_BASE: () => {},
543
- JUMP_INTO_NUMERATOR: () => {},
544
- JUMP_OUT_NUMERATOR: () => {},
545
- JUMP_OUT_DENOMINATOR: () => {},
546
- NOOP: () => {},
547
- MANY: () => {},
548
- NUM_0: buildGenericCallback("0"),
549
- NUM_1: buildGenericCallback("1"),
550
- NUM_2: buildGenericCallback("2"),
551
- NUM_3: buildGenericCallback("3"),
552
- NUM_4: buildGenericCallback("4"),
553
- NUM_5: buildGenericCallback("5"),
554
- NUM_6: buildGenericCallback("6"),
555
- NUM_7: buildGenericCallback("7"),
556
- NUM_8: buildGenericCallback("8"),
557
- NUM_9: buildGenericCallback("9"),
558
- a: buildGenericCallback("a"),
559
- b: buildGenericCallback("b"),
560
- c: buildGenericCallback("c"),
561
- d: buildGenericCallback("d"),
562
- e: buildGenericCallback("e"),
563
- f: buildGenericCallback("f"),
564
- g: buildGenericCallback("g"),
565
- h: buildGenericCallback("h"),
566
- i: buildGenericCallback("i"),
567
- j: buildGenericCallback("j"),
568
- k: buildGenericCallback("k"),
569
- l: buildGenericCallback("l"),
570
- m: buildGenericCallback("m"),
571
- n: buildGenericCallback("n"),
572
- o: buildGenericCallback("o"),
573
- p: buildGenericCallback("p"),
574
- q: buildGenericCallback("q"),
575
- r: buildGenericCallback("r"),
576
- s: buildGenericCallback("s"),
577
- t: buildGenericCallback("t"),
578
- u: buildGenericCallback("u"),
579
- v: buildGenericCallback("v"),
580
- w: buildGenericCallback("w"),
581
- x: buildGenericCallback("x"),
582
- y: buildGenericCallback("y"),
583
- z: buildGenericCallback("z"),
584
- A: buildGenericCallback("A"),
585
- B: buildGenericCallback("B"),
586
- C: buildGenericCallback("C"),
587
- D: buildGenericCallback("D"),
588
- E: buildGenericCallback("E"),
589
- F: buildGenericCallback("F"),
590
- G: buildGenericCallback("G"),
591
- H: buildGenericCallback("H"),
592
- I: buildGenericCallback("I"),
593
- J: buildGenericCallback("J"),
594
- K: buildGenericCallback("K"),
595
- L: buildGenericCallback("L"),
596
- M: buildGenericCallback("M"),
597
- N: buildGenericCallback("N"),
598
- O: buildGenericCallback("O"),
599
- P: buildGenericCallback("P"),
600
- Q: buildGenericCallback("Q"),
601
- R: buildGenericCallback("R"),
602
- S: buildGenericCallback("S"),
603
- T: buildGenericCallback("T"),
604
- U: buildGenericCallback("U"),
605
- V: buildGenericCallback("V"),
606
- W: buildGenericCallback("W"),
607
- X: buildGenericCallback("X"),
608
- Y: buildGenericCallback("Y"),
609
- Z: buildGenericCallback("Z")
610
- };
374
+ /**
375
+ * Creates a new [MathField](http://docs.mathquill.com/en/latest/Api_Methods/#mqmathfieldhtml_element-config)
376
+ * instance within the given `container`.
377
+ *
378
+ * An optional configuration callback can be provided to customize
379
+ * the created MathField. A default configuration is passed to this
380
+ * callback which can then be adjusted as needed. The configuration
381
+ * returned from this callback is used to create the MathField.
382
+ * This allows callers to do minimal configuration as only configs
383
+ * that vary from the default need to be provided.
384
+ */
385
+ function createMathField(container, configCallback) {
386
+ const baseConfig = createBaseConfig();
387
+ const config = configCallback ? configCallback(baseConfig) : baseConfig;
388
+ return mathQuillInstance.MathField(container, config);
389
+ }
611
390
 
612
391
  let MathFieldActionType = /*#__PURE__*/function (MathFieldActionType) {
613
392
  MathFieldActionType["WRITE"] = "write";
@@ -678,7 +457,7 @@ function isInsideLogIndex(cursor) {
678
457
  return false;
679
458
  }
680
459
  function isInsideEmptyNode(cursor) {
681
- return cursor[MQ.L] === MathFieldActionType.MQ_END && cursor[MQ.R] === MathFieldActionType.MQ_END;
460
+ return cursor[mathQuillInstance.L] === MathFieldActionType.MQ_END && cursor[mathQuillInstance.R] === MathFieldActionType.MQ_END;
682
461
  }
683
462
  function selectNode(node, cursor) {
684
463
  cursor.insLeftOf(node);
@@ -738,7 +517,7 @@ function maybeFindCommand(initialNode) {
738
517
  } else {
739
518
  break;
740
519
  }
741
- node = node[MQ.L];
520
+ node = node[mathQuillInstance.L];
742
521
  }
743
522
 
744
523
  // If we hit the start of a command, then grab the rest of it by
@@ -746,7 +525,7 @@ function maybeFindCommand(initialNode) {
746
525
  // with its terminal node.
747
526
  if (startNode) {
748
527
  // Next, iterate from the start to the right.
749
- node = initialNode[MQ.R];
528
+ node = initialNode[mathQuillInstance.R];
750
529
  while (node !== 0) {
751
530
  const ctrlSeq = node.ctrlSeq.trim();
752
531
  if (commandCharRegex.test(ctrlSeq)) {
@@ -759,7 +538,7 @@ function maybeFindCommand(initialNode) {
759
538
  endNode = node;
760
539
  break;
761
540
  }
762
- node = node[MQ.R];
541
+ node = node[mathQuillInstance.R];
763
542
  }
764
543
  if (validCommands.includes(name)) {
765
544
  return {
@@ -785,18 +564,18 @@ function maybeFindCommand(initialNode) {
785
564
  * name (`name`) of the command
786
565
  */
787
566
  function maybeFindCommandBeforeParens(leftParenNode) {
788
- return maybeFindCommand(leftParenNode[MQ.L]);
567
+ return maybeFindCommand(leftParenNode[mathQuillInstance.L]);
789
568
  }
790
569
  function contextForCursor(cursor) {
791
570
  // First, try to find any fraction to the right, unimpeded.
792
571
  let visitor = cursor;
793
- while (visitor[MQ.R] !== MathFieldActionType.MQ_END) {
794
- if (isFraction(visitor[MQ.R])) {
572
+ while (visitor[mathQuillInstance.R] !== MathFieldActionType.MQ_END) {
573
+ if (isFraction(visitor[mathQuillInstance.R])) {
795
574
  return CursorContext.BEFORE_FRACTION;
796
- } else if (!isLeaf(visitor[MQ.R])) {
575
+ } else if (!isLeaf(visitor[mathQuillInstance.R])) {
797
576
  break;
798
577
  }
799
- visitor = visitor[MQ.R];
578
+ visitor = visitor[mathQuillInstance.R];
800
579
  }
801
580
 
802
581
  // If that didn't work, check if the parent or grandparent is a special
@@ -816,57 +595,8 @@ function contextForCursor(cursor) {
816
595
  }
817
596
  }
818
597
 
819
- function handleLeftArrow(mathField, cursor) {
820
- // If we're inside a function, and just after the left parentheses, we
821
- // need to skip the entire function name, rather than move the cursor
822
- // inside of it. For example, when hitting left from within the
823
- // parentheses in `cos()`, we want to place the cursor to the left of
824
- // the entire expression, rather than between the `s` and the left
825
- // parenthesis.
826
- // From the cursor's perspective, this requires that our left node is
827
- // the ActionType.MQ_END node, that our grandparent is the left parenthesis, and
828
- // the nodes to the left of our grandparent comprise a valid function
829
- // name.
830
- if (cursor[MQ.L] === MathFieldActionType.MQ_END) {
831
- const parent = cursor.parent;
832
- const grandparent = parent.parent;
833
- if (grandparent.ctrlSeq === "\\left(") {
834
- const command = maybeFindCommandBeforeParens(grandparent);
835
- if (command) {
836
- cursor.insLeftOf(command.startNode);
837
- return;
838
- }
839
- }
840
- }
841
-
842
- // Otherwise, we default to the standard MathQull left behavior.
843
- mathField.keystroke("Left");
844
- }
845
- function handleRightArrow(mathField, cursor) {
846
- const command = maybeFindCommand(cursor[MQ.R]);
847
- if (command) {
848
- // Similarly, if a function is to our right, then we need to place
849
- // the cursor at the start of its parenthetical content, which is
850
- // done by putting it to the left of ites parentheses and then
851
- // moving right once.
852
- cursor.insLeftOf(command.endNode);
853
- mathField.keystroke("Right");
854
- } else {
855
- // Otherwise, we default to the standard MathQull right behavior.
856
- mathField.keystroke("Right");
857
- }
858
- }
859
- function handleArrow(mathField, key) {
860
- const cursor = getCursor(mathField);
861
- if (key === "LEFT") {
862
- handleLeftArrow(mathField, cursor);
863
- } else if (key === "RIGHT") {
864
- handleRightArrow(mathField, cursor);
865
- }
866
- }
867
-
868
598
  function handleBackspaceInNthRoot(mathField, cursor) {
869
- const isAtLeftEnd = cursor[MQ.L] === MathFieldActionType.MQ_END;
599
+ const isAtLeftEnd = cursor[mathQuillInstance.L] === MathFieldActionType.MQ_END;
870
600
  const isRootEmpty = isInsideEmptyNode(cursor.parent.parent.blocks[0].ends);
871
601
  if (isAtLeftEnd) {
872
602
  selectNode(cursor.parent.parent, cursor);
@@ -885,7 +615,7 @@ function handleBackspaceInRootIndex(mathField, cursor) {
885
615
 
886
616
  const grandparent = cursor.parent.parent;
887
617
  const latex = grandparent.latex();
888
- const reinsertionPoint = grandparent[MQ.L];
618
+ const reinsertionPoint = grandparent[mathQuillInstance.L];
889
619
  selectNode(grandparent, cursor);
890
620
  const rootIsEmpty = grandparent.blocks[1].jQ.text() === "";
891
621
  if (rootIsEmpty) {
@@ -904,13 +634,13 @@ function handleBackspaceInRootIndex(mathField, cursor) {
904
634
 
905
635
  // Adjust the cursor to be to the left the sqrt.
906
636
  if (reinsertionPoint === MathFieldActionType.MQ_END) {
907
- mathField.moveToDirEnd(MQ.L);
637
+ mathField.moveToDirEnd(mathQuillInstance.L);
908
638
  } else {
909
639
  cursor.insRightOf(reinsertionPoint);
910
640
  }
911
641
  }
912
642
  } else {
913
- if (cursor[MQ.L] !== MathFieldActionType.MQ_END) {
643
+ if (cursor[mathQuillInstance.L] !== MathFieldActionType.MQ_END) {
914
644
  // If the cursor is not at the leftmost position inside the
915
645
  // root's index, delete a character.
916
646
  mathField.keystroke("Backspace");
@@ -923,14 +653,14 @@ function handleBackspaceInLogIndex(mathField, cursor) {
923
653
  const command = maybeFindCommandBeforeParens(grandparent);
924
654
  cursor.insLeftOf(command == null ? void 0 : command.startNode);
925
655
  cursor.startSelection();
926
- if (grandparent[MQ.R] !== MathFieldActionType.MQ_END) {
927
- cursor.insRightOf(grandparent[MQ.R]);
656
+ if (grandparent[mathQuillInstance.R] !== MathFieldActionType.MQ_END) {
657
+ cursor.insRightOf(grandparent[mathQuillInstance.R]);
928
658
  } else {
929
659
  cursor.insRightOf(grandparent);
930
660
  }
931
661
  cursor.select();
932
662
  cursor.endSelection();
933
- const isLogBodyEmpty = grandparent[MQ.R].contentjQ.text() === "";
663
+ const isLogBodyEmpty = grandparent[mathQuillInstance.R].contentjQ.text() === "";
934
664
  if (isLogBodyEmpty) {
935
665
  // If there's no content inside the log's parens then delete the
936
666
  // whole thing.
@@ -949,8 +679,8 @@ function handleBackspaceOutsideParens(cursor) {
949
679
  // (x+1)| => |(x+1)|
950
680
  // \log(x+1)| => |\log(x+1)|
951
681
 
952
- const leftNode = cursor[MQ.L];
953
- const rightNode = cursor[MQ.R];
682
+ const leftNode = cursor[mathQuillInstance.L];
683
+ const rightNode = cursor[mathQuillInstance.R];
954
684
  const command = maybeFindCommandBeforeParens(leftNode);
955
685
  if (command && command.startNode) {
956
686
  // There's a command before the parens so we select it as well as
@@ -996,7 +726,7 @@ function handleBackspaceInsideParens(mathField, cursor) {
996
726
  // - \log(|x+1) => |\log(x+1)|
997
727
  // - \log(|) => |
998
728
 
999
- if (cursor[MQ.L] !== MathFieldActionType.MQ_END) {
729
+ if (cursor[mathQuillInstance.L] !== MathFieldActionType.MQ_END) {
1000
730
  // This command contains math and there's some math to
1001
731
  // the left of the cursor that we should delete normally
1002
732
  // before doing anything special.
@@ -1009,12 +739,12 @@ function handleBackspaceInsideParens(mathField, cursor) {
1009
739
  // has a subscript as is the case in log_n then move the cursor into
1010
740
  // the subscript, e.g. \log_{5}(|x+1) => \log_{5|}(x+1)
1011
741
 
1012
- if (grandparent[MQ.L].sub) {
742
+ if (grandparent[mathQuillInstance.L].sub) {
1013
743
  // if there is a subscript
1014
- if (grandparent[MQ.L].sub.jQ.text()) {
744
+ if (grandparent[mathQuillInstance.L].sub.jQ.text()) {
1015
745
  // and it contains text
1016
746
  // move the cursor to the right end of the subscript
1017
- cursor.insAtRightEnd(grandparent[MQ.L].sub);
747
+ cursor.insAtRightEnd(grandparent[mathQuillInstance.L].sub);
1018
748
  return;
1019
749
  }
1020
750
  }
@@ -1052,7 +782,7 @@ function handleBackspace(mathField) {
1052
782
  if (!cursor.selection) {
1053
783
  const parent = cursor.parent;
1054
784
  const grandparent = parent.parent;
1055
- const leftNode = cursor[MQ.L];
785
+ const leftNode = cursor[mathQuillInstance.L];
1056
786
  if (isFraction(leftNode)) {
1057
787
  selectNode(leftNode, cursor);
1058
788
  } else if (isSquareRoot(leftNode)) {
@@ -1079,6 +809,133 @@ function handleBackspace(mathField) {
1079
809
  }
1080
810
  }
1081
811
 
812
+ /**
813
+ * Constants that are shared between multiple files.
814
+ */
815
+
816
+ let KeypadType = /*#__PURE__*/function (KeypadType) {
817
+ KeypadType["FRACTION"] = "FRACTION";
818
+ KeypadType["EXPRESSION"] = "EXPRESSION";
819
+ return KeypadType;
820
+ }({});
821
+ const KeyTypes = ["EMPTY",
822
+ // For numerals, variables, and any other characters that themselves
823
+ // compose 'values'.
824
+ "VALUE",
825
+ // For buttons that insert or adjust math in an input.
826
+ "OPERATOR",
827
+ // For buttons that move the cursor in an input (including via
828
+ // deletion).
829
+ "INPUT_NAVIGATION",
830
+ // For buttons that modify the broader keypad state (e.g., by changing
831
+ // the visible pane).
832
+ "KEYPAD_NAVIGATION",
833
+ // For buttons that house multiple buttons and have no action
834
+ // themselves.
835
+ "MANY",
836
+ // For the echo animation that appears on press.
837
+ "ECHO"];
838
+ let DeviceOrientation = /*#__PURE__*/function (DeviceOrientation) {
839
+ DeviceOrientation["LANDSCAPE"] = "LANDSCAPE";
840
+ DeviceOrientation["PORTRAIT"] = "PORTRAIT";
841
+ return DeviceOrientation;
842
+ }({});
843
+ let DeviceType = /*#__PURE__*/function (DeviceType) {
844
+ DeviceType["PHONE"] = "PHONE";
845
+ DeviceType["TABLET"] = "TABLET";
846
+ return DeviceType;
847
+ }({});
848
+ let LayoutMode = /*#__PURE__*/function (LayoutMode) {
849
+ LayoutMode["FULLSCREEN"] = "FULLSCREEN";
850
+ LayoutMode["COMPACT"] = "COMPACT";
851
+ return LayoutMode;
852
+ }({});
853
+ let BorderDirection = /*#__PURE__*/function (BorderDirection) {
854
+ BorderDirection["LEFT"] = "LEFT";
855
+ BorderDirection["BOTTOM"] = "BOTTOM";
856
+ return BorderDirection;
857
+ }({});
858
+ const BorderStyles = {
859
+ LEFT: [BorderDirection.LEFT],
860
+ BOTTOM: [BorderDirection.BOTTOM],
861
+ ALL: [BorderDirection.LEFT, BorderDirection.BOTTOM],
862
+ NONE: []
863
+ };
864
+ let IconType = /*#__PURE__*/function (IconType) {
865
+ IconType["MATH"] = "MATH";
866
+ IconType["SVG"] = "SVG";
867
+ IconType["TEXT"] = "TEXT";
868
+ return IconType;
869
+ }({});
870
+ let DecimalSeparator = /*#__PURE__*/function (DecimalSeparator) {
871
+ DecimalSeparator["COMMA"] = "COMMA";
872
+ DecimalSeparator["PERIOD"] = "PERIOD";
873
+ return DecimalSeparator;
874
+ }({});
875
+ let EchoAnimationType = /*#__PURE__*/function (EchoAnimationType) {
876
+ EchoAnimationType["SLIDE_AND_FADE"] = "SLIDE_AND_FADE";
877
+ EchoAnimationType["FADE_ONLY"] = "FADE_ONLY";
878
+ EchoAnimationType["LONG_FADE_ONLY"] = "LONG_FADE_ONLY";
879
+ return EchoAnimationType;
880
+ }({});
881
+
882
+ // NOTES(kevinb):
883
+ // - In order to get the correct decimal separator for the current locale,
884
+ // the locale must bet set using `setLocale(kaLocale)` which can be
885
+ // imported from wonder-blocks-i18n.
886
+ // - Some languages/locales use different decimal separators than the ones
887
+ // listed here. Much of the Arab world uses U+066C.
888
+ const decimalSeparator = getDecimalSeparator() === "," ? DecimalSeparator.COMMA : DecimalSeparator.PERIOD;
889
+
890
+ function handleLeftArrow(mathField, cursor) {
891
+ // If we're inside a function, and just after the left parentheses, we
892
+ // need to skip the entire function name, rather than move the cursor
893
+ // inside of it. For example, when hitting left from within the
894
+ // parentheses in `cos()`, we want to place the cursor to the left of
895
+ // the entire expression, rather than between the `s` and the left
896
+ // parenthesis.
897
+ // From the cursor's perspective, this requires that our left node is
898
+ // the ActionType.MQ_END node, that our grandparent is the left parenthesis, and
899
+ // the nodes to the left of our grandparent comprise a valid function
900
+ // name.
901
+ if (cursor[mathQuillInstance.L] === MathFieldActionType.MQ_END) {
902
+ const parent = cursor.parent;
903
+ const grandparent = parent.parent;
904
+ if (grandparent.ctrlSeq === "\\left(") {
905
+ const command = maybeFindCommandBeforeParens(grandparent);
906
+ if (command) {
907
+ cursor.insLeftOf(command.startNode);
908
+ return;
909
+ }
910
+ }
911
+ }
912
+
913
+ // Otherwise, we default to the standard MathQull left behavior.
914
+ mathField.keystroke("Left");
915
+ }
916
+ function handleRightArrow(mathField, cursor) {
917
+ const command = maybeFindCommand(cursor[mathQuillInstance.R]);
918
+ if (command) {
919
+ // Similarly, if a function is to our right, then we need to place
920
+ // the cursor at the start of its parenthetical content, which is
921
+ // done by putting it to the left of ites parentheses and then
922
+ // moving right once.
923
+ cursor.insLeftOf(command.endNode);
924
+ mathField.keystroke("Right");
925
+ } else {
926
+ // Otherwise, we default to the standard MathQull right behavior.
927
+ mathField.keystroke("Right");
928
+ }
929
+ }
930
+ function handleArrow(mathField, key) {
931
+ const cursor = getCursor(mathField);
932
+ if (key === "LEFT") {
933
+ handleLeftArrow(mathField, cursor);
934
+ } else if (key === "RIGHT") {
935
+ handleRightArrow(mathField, cursor);
936
+ }
937
+ }
938
+
1082
939
  const ArithmeticOperators = ["+", "-", "\\cdot", "\\times", "\\div"];
1083
940
  const EqualityOperators = ["=", "\\neq", "<", "\\leq", ">", "\\geq"];
1084
941
  function handleExponent(mathField, key) {
@@ -1087,7 +944,7 @@ function handleExponent(mathField, key) {
1087
944
  // knowingly cannot be raised to a power), add an empty set of
1088
945
  // parentheses and apply the exponent to that.
1089
946
  const invalidPrefixes = [...ArithmeticOperators, ...EqualityOperators];
1090
- const precedingNode = cursor[MQ.L];
947
+ const precedingNode = cursor[mathQuillInstance.L];
1091
948
  const shouldPrefixWithParens = precedingNode === MathFieldActionType.MQ_END || invalidPrefixes.includes(precedingNode.ctrlSeq.trim());
1092
949
  if (shouldPrefixWithParens) {
1093
950
  mathField.write("\\left(\\right)");
@@ -1153,11 +1010,11 @@ function handleJumpOut(mathField, key) {
1153
1010
  // Find the nearest fraction to the right of the cursor.
1154
1011
  let fractionNode;
1155
1012
  let visitor = cursor;
1156
- while (visitor[MQ.R] !== MathFieldActionType.MQ_END) {
1157
- if (isFraction(visitor[MQ.R])) {
1158
- fractionNode = visitor[MQ.R];
1013
+ while (visitor[mathQuillInstance.R] !== MathFieldActionType.MQ_END) {
1014
+ if (isFraction(visitor[mathQuillInstance.R])) {
1015
+ fractionNode = visitor[mathQuillInstance.R];
1159
1016
  }
1160
- visitor = visitor[MQ.R];
1017
+ visitor = visitor[mathQuillInstance.R];
1161
1018
  }
1162
1019
 
1163
1020
  // Jump into it!
@@ -1186,7 +1043,7 @@ function handleJumpOut(mathField, key) {
1186
1043
  // Navigate right once more, if we're right before parens. This
1187
1044
  // is to handle the standard case in which the subscript is the
1188
1045
  // base of a custom log.
1189
- if (isParens(cursor[MQ.R])) {
1046
+ if (isParens(cursor[mathQuillInstance.R])) {
1190
1047
  mathField.keystroke("Right");
1191
1048
  }
1192
1049
  break;
@@ -1199,25 +1056,45 @@ function handleJumpOut(mathField, key) {
1199
1056
  }
1200
1057
  }
1201
1058
 
1059
+ var ActionType = /*#__PURE__*/function (ActionType) {
1060
+ ActionType["WRITE"] = "write";
1061
+ ActionType["CMD"] = "cmd";
1062
+ ActionType["KEYSTROKE"] = "keystroke";
1063
+ ActionType[ActionType["MQ_END"] = 0] = "MQ_END";
1064
+ return ActionType;
1065
+ }(ActionType || {});
1066
+ const decimalSymbol = decimalSeparator === DecimalSeparator.COMMA ? "," : ".";
1067
+ function buildGenericCallback(str, type = ActionType.WRITE) {
1068
+ return function (mathQuill) {
1069
+ switch (type) {
1070
+ case ActionType.WRITE:
1071
+ {
1072
+ mathQuill.write(str);
1073
+ return;
1074
+ }
1075
+ case ActionType.CMD:
1076
+ {
1077
+ mathQuill.cmd(str);
1078
+ return;
1079
+ }
1080
+ case ActionType.KEYSTROKE:
1081
+ {
1082
+ mathQuill.keystroke(str);
1083
+ return;
1084
+ }
1085
+ }
1086
+ };
1087
+ }
1202
1088
  function buildNormalFunctionCallback(command) {
1203
1089
  return function (mathField) {
1204
1090
  mathField.write(`\\${command}\\left(\\right)`);
1205
1091
  mathField.keystroke("Left");
1206
1092
  };
1207
1093
  }
1208
- const customKeyTranslator = _extends({}, keyToMathquillMap, {
1209
- // note(Matthew): in all likelihood, this should be moved
1210
- // to the shared key2MathQuill translator. During this refactor
1211
- // I tried to keep logic the same while deduplicating code.
1212
- // Perseus' Expression MathInput treats this stuff differently
1213
- // (or doesn't do anything with them at all), so I kept it that way
1214
- BACKSPACE: handleBackspace,
1094
+ const keyToMathquillMap = {
1215
1095
  EXP: handleExponent,
1216
1096
  EXP_2: handleExponent,
1217
1097
  EXP_3: handleExponent,
1218
- FRAC: mathQuill => {
1219
- mathQuill.cmd("\\frac");
1220
- },
1221
1098
  JUMP_OUT_PARENTHESES: handleJumpOut,
1222
1099
  JUMP_OUT_EXPONENT: handleJumpOut,
1223
1100
  JUMP_OUT_BASE: handleJumpOut,
@@ -1230,7 +1107,157 @@ const customKeyTranslator = _extends({}, keyToMathquillMap, {
1230
1107
  LN: buildNormalFunctionCallback("ln"),
1231
1108
  SIN: buildNormalFunctionCallback("sin"),
1232
1109
  COS: buildNormalFunctionCallback("cos"),
1233
- TAN: buildNormalFunctionCallback("tan")
1110
+ TAN: buildNormalFunctionCallback("tan"),
1111
+ CDOT: buildGenericCallback("\\cdot"),
1112
+ DECIMAL: buildGenericCallback(decimalSymbol),
1113
+ DIVIDE: buildGenericCallback("\\div"),
1114
+ EQUAL: buildGenericCallback("="),
1115
+ GEQ: buildGenericCallback("\\geq"),
1116
+ GT: buildGenericCallback(">"),
1117
+ LEQ: buildGenericCallback("\\leq"),
1118
+ LT: buildGenericCallback("<"),
1119
+ MINUS: buildGenericCallback("-"),
1120
+ NEGATIVE: buildGenericCallback("-"),
1121
+ NEQ: buildGenericCallback("\\neq"),
1122
+ PERCENT: buildGenericCallback("%"),
1123
+ PERIOD: buildGenericCallback("."),
1124
+ PLUS: buildGenericCallback("+"),
1125
+ TIMES: buildGenericCallback("\\times"),
1126
+ // The `FRAC_EXCLUSIVE` variant is handled manually, since we may need to do
1127
+ // some additional navigation depending on the cursor position.
1128
+ FRAC_INCLUSIVE: buildGenericCallback("/", ActionType.CMD),
1129
+ FRAC: buildGenericCallback("\\frac", ActionType.CMD),
1130
+ LEFT_PAREN: buildGenericCallback("(", ActionType.CMD),
1131
+ RIGHT_PAREN: buildGenericCallback(")", ActionType.CMD),
1132
+ SQRT: buildGenericCallback("sqrt", ActionType.CMD),
1133
+ PHI: buildGenericCallback("\\phi", ActionType.CMD),
1134
+ PI: buildGenericCallback("pi", ActionType.CMD),
1135
+ THETA: buildGenericCallback("theta", ActionType.CMD),
1136
+ RADICAL: buildGenericCallback("nthroot", ActionType.CMD),
1137
+ BACKSPACE: buildGenericCallback("Backspace", ActionType.KEYSTROKE),
1138
+ UP: buildGenericCallback("Up", ActionType.KEYSTROKE),
1139
+ DOWN: buildGenericCallback("Down", ActionType.KEYSTROKE),
1140
+ CUBE_ROOT: mathQuill => {
1141
+ mathQuill.write("\\sqrt[3]{}");
1142
+ mathQuill.keystroke("Left"); // under the root
1143
+ },
1144
+
1145
+ FRAC_EXCLUSIVE: mathQuill => {
1146
+ const cursor = mathQuill.__controller.cursor;
1147
+ // If there's nothing to the left of the cursor, then we want to
1148
+ // leave the cursor to the left of the fraction after creating it.
1149
+ const shouldNavigateLeft = cursor[mathQuillInstance.L] === ActionType.MQ_END;
1150
+ mathQuill.cmd("\\frac");
1151
+ if (shouldNavigateLeft) {
1152
+ mathQuill.keystroke("Left");
1153
+ }
1154
+ },
1155
+ LOG_B: mathQuill => {
1156
+ mathQuill.typedText("log_");
1157
+ mathQuill.keystroke("Right");
1158
+ mathQuill.typedText("(");
1159
+ mathQuill.keystroke("Left");
1160
+ mathQuill.keystroke("Left");
1161
+ },
1162
+ LOG_N: mathQuill => {
1163
+ mathQuill.write("log_{ }\\left(\\right)");
1164
+ mathQuill.keystroke("Left"); // into parentheses
1165
+ mathQuill.keystroke("Left"); // out of parentheses
1166
+ mathQuill.keystroke("Left"); // into index
1167
+ },
1168
+
1169
+ NTHROOT3: mathQuill => {
1170
+ mathQuill.typedText("nthroot3");
1171
+ mathQuill.keystroke("Right");
1172
+ },
1173
+ POW: mathQuill => {
1174
+ const contents = mathQuill.latex();
1175
+ mathQuill.typedText("^");
1176
+
1177
+ // If the input hasn't changed (for example, if we're
1178
+ // attempting to add an exponent on an empty input or an empty
1179
+ // denominator), insert our own "a^b"
1180
+ if (mathQuill.latex() === contents) {
1181
+ mathQuill.typedText("a^b");
1182
+ }
1183
+ },
1184
+ // These need to be overwritten by the consumer
1185
+ // if they're going to be used
1186
+ DISMISS: () => {},
1187
+ NOOP: () => {},
1188
+ MANY: () => {},
1189
+ NUM_0: buildGenericCallback("0"),
1190
+ NUM_1: buildGenericCallback("1"),
1191
+ NUM_2: buildGenericCallback("2"),
1192
+ NUM_3: buildGenericCallback("3"),
1193
+ NUM_4: buildGenericCallback("4"),
1194
+ NUM_5: buildGenericCallback("5"),
1195
+ NUM_6: buildGenericCallback("6"),
1196
+ NUM_7: buildGenericCallback("7"),
1197
+ NUM_8: buildGenericCallback("8"),
1198
+ NUM_9: buildGenericCallback("9"),
1199
+ a: buildGenericCallback("a"),
1200
+ b: buildGenericCallback("b"),
1201
+ c: buildGenericCallback("c"),
1202
+ d: buildGenericCallback("d"),
1203
+ e: buildGenericCallback("e"),
1204
+ f: buildGenericCallback("f"),
1205
+ g: buildGenericCallback("g"),
1206
+ h: buildGenericCallback("h"),
1207
+ i: buildGenericCallback("i"),
1208
+ j: buildGenericCallback("j"),
1209
+ k: buildGenericCallback("k"),
1210
+ l: buildGenericCallback("l"),
1211
+ m: buildGenericCallback("m"),
1212
+ n: buildGenericCallback("n"),
1213
+ o: buildGenericCallback("o"),
1214
+ p: buildGenericCallback("p"),
1215
+ q: buildGenericCallback("q"),
1216
+ r: buildGenericCallback("r"),
1217
+ s: buildGenericCallback("s"),
1218
+ t: buildGenericCallback("t"),
1219
+ u: buildGenericCallback("u"),
1220
+ v: buildGenericCallback("v"),
1221
+ w: buildGenericCallback("w"),
1222
+ x: buildGenericCallback("x"),
1223
+ y: buildGenericCallback("y"),
1224
+ z: buildGenericCallback("z"),
1225
+ A: buildGenericCallback("A"),
1226
+ B: buildGenericCallback("B"),
1227
+ C: buildGenericCallback("C"),
1228
+ D: buildGenericCallback("D"),
1229
+ E: buildGenericCallback("E"),
1230
+ F: buildGenericCallback("F"),
1231
+ G: buildGenericCallback("G"),
1232
+ H: buildGenericCallback("H"),
1233
+ I: buildGenericCallback("I"),
1234
+ J: buildGenericCallback("J"),
1235
+ K: buildGenericCallback("K"),
1236
+ L: buildGenericCallback("L"),
1237
+ M: buildGenericCallback("M"),
1238
+ N: buildGenericCallback("N"),
1239
+ O: buildGenericCallback("O"),
1240
+ P: buildGenericCallback("P"),
1241
+ Q: buildGenericCallback("Q"),
1242
+ R: buildGenericCallback("R"),
1243
+ S: buildGenericCallback("S"),
1244
+ T: buildGenericCallback("T"),
1245
+ U: buildGenericCallback("U"),
1246
+ V: buildGenericCallback("V"),
1247
+ W: buildGenericCallback("W"),
1248
+ X: buildGenericCallback("X"),
1249
+ Y: buildGenericCallback("Y"),
1250
+ Z: buildGenericCallback("Z")
1251
+ };
1252
+
1253
+ const mobileKeyTranslator = _extends({}, keyToMathquillMap, {
1254
+ // note(Matthew): our mobile backspace logic is really complicated
1255
+ // and for some reason doesn't really work in the desktop experience.
1256
+ // So we default to the basic backspace functionality in the
1257
+ // key translator and overwrite it with the complicated logic here
1258
+ // until we can unify the experiences (if we even want to).
1259
+ // https://khanacademy.atlassian.net/browse/LC-906
1260
+ BACKSPACE: handleBackspace
1234
1261
  });
1235
1262
 
1236
1263
  /**
@@ -1239,17 +1266,19 @@ const customKeyTranslator = _extends({}, keyToMathquillMap, {
1239
1266
  * from MathQuill changes.
1240
1267
  */
1241
1268
  class MathWrapper {
1242
- // MathQuill input
1269
+ // MathQuill MathField input
1243
1270
 
1244
- constructor(element, options = {}, callbacks = {}) {
1271
+ constructor(element, callbacks = {}) {
1245
1272
  this.mathField = void 0;
1246
1273
  this.callbacks = void 0;
1247
- this.mathField = MQ.MathField(element, {
1248
- // use a span instead of a textarea so that we don't bring up the
1249
- // native keyboard on mobile when selecting the input
1250
- substituteTextarea: function () {
1251
- return document.createElement("span");
1252
- }
1274
+ this.mathField = createMathField(element, () => {
1275
+ return {
1276
+ // use a span instead of a textarea so that we don't bring up the
1277
+ // native keyboard on mobile when selecting the input
1278
+ substituteTextarea: function () {
1279
+ return document.createElement("span");
1280
+ }
1281
+ };
1253
1282
  });
1254
1283
  this.callbacks = callbacks;
1255
1284
  }
@@ -1279,7 +1308,7 @@ class MathWrapper {
1279
1308
  */
1280
1309
  pressKey(key) {
1281
1310
  const cursor = this.getCursor();
1282
- const translator = customKeyTranslator[key];
1311
+ const translator = mobileKeyTranslator[key];
1283
1312
  if (translator) {
1284
1313
  translator(this.mathField, key);
1285
1314
  }
@@ -1327,7 +1356,7 @@ class MathWrapper {
1327
1356
  // Unless that would leave us mid-command, in which case, we
1328
1357
  // need to adjust and place the cursor inside the parens
1329
1358
  // following the command.
1330
- const command = maybeFindCommand(cursor[MQ.L]);
1359
+ const command = maybeFindCommand(cursor[mathQuillInstance.L]);
1331
1360
  if (command && command.endNode) {
1332
1361
  // NOTE(charlie): endNode should definitely be \left(.
1333
1362
  cursor.insLeftOf(command.endNode);
@@ -1898,7 +1927,7 @@ class MathInput extends React.Component {
1898
1927
  }
1899
1928
  componentDidMount() {
1900
1929
  this._isMounted = true;
1901
- this.mathField = new MathWrapper(this._mathContainer, {}, {
1930
+ this.mathField = new MathWrapper(this._mathContainer, {
1902
1931
  onCursorMove: cursor => {
1903
1932
  // TODO(charlie): It's not great that there is so much coupling
1904
1933
  // between this keypad and the input behavior. We should wrap
@@ -8161,7 +8190,7 @@ const KeypadButton = ({
8161
8190
  onPress: () => onClickKey(keyConfig.id),
8162
8191
  tintColor: tintColor,
8163
8192
  style: style,
8164
- ariaLabel: keyConfig.id
8193
+ ariaLabel: keyConfig.ariaLabel
8165
8194
  }, /*#__PURE__*/React.createElement(ButtonAsset, {
8166
8195
  id: keyConfig.id
8167
8196
  }));
@@ -8563,5 +8592,5 @@ const styles = StyleSheet.create({
8563
8592
  }
8564
8593
  });
8565
8594
 
8566
- export { CursorContext, KeyConfigs, Keypad, MathInput as KeypadInput, KeypadType, ProvidedKeypad as LegacyKeypad, keyToMathquillMap as keyTranslator, keypadElementPropType };
8595
+ export { CursorContext, KeyConfigs, Keypad, MathInput as KeypadInput, KeypadType, ProvidedKeypad as LegacyKeypad, createMathField, keyToMathquillMap as keyTranslator, keypadElementPropType, mathQuillInstance };
8567
8596
  //# sourceMappingURL=index.js.map