@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/index.js CHANGED
@@ -401,274 +401,52 @@ class DragListener {
401
401
  }
402
402
  }
403
403
 
404
- /**
405
- * Constants that are shared between multiple files.
406
- */
407
-
408
- let KeypadType = /*#__PURE__*/function (KeypadType) {
409
- KeypadType["FRACTION"] = "FRACTION";
410
- KeypadType["EXPRESSION"] = "EXPRESSION";
411
- return KeypadType;
412
- }({});
413
- const KeyTypes = ["EMPTY",
414
- // For numerals, variables, and any other characters that themselves
415
- // compose 'values'.
416
- "VALUE",
417
- // For buttons that insert or adjust math in an input.
418
- "OPERATOR",
419
- // For buttons that move the cursor in an input (including via
420
- // deletion).
421
- "INPUT_NAVIGATION",
422
- // For buttons that modify the broader keypad state (e.g., by changing
423
- // the visible pane).
424
- "KEYPAD_NAVIGATION",
425
- // For buttons that house multiple buttons and have no action
426
- // themselves.
427
- "MANY",
428
- // For the echo animation that appears on press.
429
- "ECHO"];
430
- let DeviceOrientation = /*#__PURE__*/function (DeviceOrientation) {
431
- DeviceOrientation["LANDSCAPE"] = "LANDSCAPE";
432
- DeviceOrientation["PORTRAIT"] = "PORTRAIT";
433
- return DeviceOrientation;
434
- }({});
435
- let DeviceType = /*#__PURE__*/function (DeviceType) {
436
- DeviceType["PHONE"] = "PHONE";
437
- DeviceType["TABLET"] = "TABLET";
438
- return DeviceType;
439
- }({});
440
- let LayoutMode = /*#__PURE__*/function (LayoutMode) {
441
- LayoutMode["FULLSCREEN"] = "FULLSCREEN";
442
- LayoutMode["COMPACT"] = "COMPACT";
443
- return LayoutMode;
444
- }({});
445
- let BorderDirection = /*#__PURE__*/function (BorderDirection) {
446
- BorderDirection["LEFT"] = "LEFT";
447
- BorderDirection["BOTTOM"] = "BOTTOM";
448
- return BorderDirection;
449
- }({});
450
- const BorderStyles = {
451
- LEFT: [BorderDirection.LEFT],
452
- BOTTOM: [BorderDirection.BOTTOM],
453
- ALL: [BorderDirection.LEFT, BorderDirection.BOTTOM],
454
- NONE: []
455
- };
456
- let IconType = /*#__PURE__*/function (IconType) {
457
- IconType["MATH"] = "MATH";
458
- IconType["SVG"] = "SVG";
459
- IconType["TEXT"] = "TEXT";
460
- return IconType;
461
- }({});
462
- let DecimalSeparator = /*#__PURE__*/function (DecimalSeparator) {
463
- DecimalSeparator["COMMA"] = "COMMA";
464
- DecimalSeparator["PERIOD"] = "PERIOD";
465
- return DecimalSeparator;
466
- }({});
467
- let EchoAnimationType = /*#__PURE__*/function (EchoAnimationType) {
468
- EchoAnimationType["SLIDE_AND_FADE"] = "SLIDE_AND_FADE";
469
- EchoAnimationType["FADE_ONLY"] = "FADE_ONLY";
470
- EchoAnimationType["LONG_FADE_ONLY"] = "LONG_FADE_ONLY";
471
- return EchoAnimationType;
472
- }({});
473
-
474
- // NOTES(kevinb):
475
- // - In order to get the correct decimal separator for the current locale,
476
- // the locale must bet set using `setLocale(kaLocale)` which can be
477
- // imported from wonder-blocks-i18n.
478
- // - Some languages/locales use different decimal separators than the ones
479
- // listed here. Much of the Arab world uses U+066C.
480
- const decimalSeparator = i18n.getDecimalSeparator() === "," ? DecimalSeparator.COMMA : DecimalSeparator.PERIOD;
481
-
482
- var MQ = MathQuill__default["default"].getInterface(2);
483
-
484
- var ActionType = /*#__PURE__*/function (ActionType) {
485
- ActionType["WRITE"] = "write";
486
- ActionType["CMD"] = "cmd";
487
- ActionType["KEYSTROKE"] = "keystroke";
488
- ActionType[ActionType["MQ_END"] = 0] = "MQ_END";
489
- return ActionType;
490
- }(ActionType || {});
491
- const decimalSymbol = decimalSeparator === DecimalSeparator.COMMA ? "," : ".";
492
- function buildGenericCallback(str) {
493
- let type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ActionType.WRITE;
494
- return function (mathQuill) {
495
- switch (type) {
496
- case ActionType.WRITE:
497
- {
498
- mathQuill.write(str);
499
- return;
500
- }
501
- case ActionType.CMD:
502
- {
503
- mathQuill.cmd(str);
504
- return;
505
- }
506
- case ActionType.KEYSTROKE:
507
- {
508
- mathQuill.keystroke(str);
509
- return;
510
- }
511
- }
404
+ // We only need one MathQuill instance (referred to as MQ in the docs)
405
+ // and that contains some MQ constants and the MathField constructor
406
+ const mathQuillInstance = MathQuill__default["default"].getInterface(2);
407
+ function createBaseConfig() {
408
+ return {
409
+ // LaTeX commands that, when typed, are immediately replaced by the
410
+ // appropriate symbol. This does not include ln, log, or any of the
411
+ // trig functions; those are always interpreted as commands.
412
+ autoCommands: "pi theta phi sqrt nthroot",
413
+ // Pop the cursor out of super/subscripts on arithmetic operators
414
+ // or (in)equalities.
415
+ charsThatBreakOutOfSupSub: "+-*/=<>≠≤≥",
416
+ // Prevent excessive super/subscripts or fractions from being
417
+ // created without operands, e.g. when somebody holds down a key
418
+ supSubsRequireOperand: true,
419
+ // The name of this option is somewhat misleading, as tabbing in
420
+ // MathQuill breaks you out of a nested context (fraction/script)
421
+ // if you're in one, but moves focus to the next input if you're
422
+ // not. Spaces (with this option enabled) are just ignored in the
423
+ // latter case.
424
+ //
425
+ // TODO(alex): In order to allow inputting mixed numbers, we will
426
+ // have to accept spaces in certain cases. The desired behavior is
427
+ // still to escape nested contexts if currently in one, but to
428
+ // insert a space if not (we don't expect mixed numbers in nested
429
+ // contexts). We should also limit to one consecutive space.
430
+ spaceBehavesLikeTab: true
512
431
  };
513
432
  }
514
- const keyToMathquillMap = {
515
- CDOT: buildGenericCallback("\\cdot"),
516
- COS: buildGenericCallback("cos"),
517
- DECIMAL: buildGenericCallback(decimalSymbol),
518
- DIVIDE: buildGenericCallback("\\div"),
519
- EQUAL: buildGenericCallback("="),
520
- EXP: buildGenericCallback("^"),
521
- EXP_2: buildGenericCallback("^2"),
522
- EXP_3: buildGenericCallback("^3"),
523
- GEQ: buildGenericCallback("\\geq"),
524
- GT: buildGenericCallback(">"),
525
- LEQ: buildGenericCallback("\\leq"),
526
- LN: buildGenericCallback("\\ln"),
527
- LOG: buildGenericCallback("\\log"),
528
- LT: buildGenericCallback("<"),
529
- MINUS: buildGenericCallback("-"),
530
- NEGATIVE: buildGenericCallback("-"),
531
- NEQ: buildGenericCallback("\\neq"),
532
- PERCENT: buildGenericCallback("%"),
533
- PERIOD: buildGenericCallback("."),
534
- PLUS: buildGenericCallback("+"),
535
- SIN: buildGenericCallback("sin"),
536
- TAN: buildGenericCallback("tan"),
537
- TIMES: buildGenericCallback("\\times"),
538
- // The `FRAC_EXCLUSIVE` variant is handled manually, since we may need to do
539
- // some additional navigation depending on the cursor position.
540
- FRAC_INCLUSIVE: buildGenericCallback("/", ActionType.CMD),
541
- LEFT_PAREN: buildGenericCallback("(", ActionType.CMD),
542
- RIGHT_PAREN: buildGenericCallback(")", ActionType.CMD),
543
- SQRT: buildGenericCallback("sqrt", ActionType.CMD),
544
- PHI: buildGenericCallback("\\phi", ActionType.CMD),
545
- PI: buildGenericCallback("pi", ActionType.CMD),
546
- THETA: buildGenericCallback("theta", ActionType.CMD),
547
- RADICAL: buildGenericCallback("nthroot", ActionType.CMD),
548
- UP: buildGenericCallback("Up", ActionType.KEYSTROKE),
549
- DOWN: buildGenericCallback("Down", ActionType.KEYSTROKE),
550
- CUBE_ROOT: mathQuill => {
551
- mathQuill.write("\\sqrt[3]{}");
552
- mathQuill.keystroke("Left"); // under the root
553
- },
554
-
555
- FRAC_EXCLUSIVE: mathQuill => {
556
- const cursor = mathQuill.__controller.cursor;
557
- // If there's nothing to the left of the cursor, then we want to
558
- // leave the cursor to the left of the fraction after creating it.
559
- const shouldNavigateLeft = cursor[MQ.L] === ActionType.MQ_END;
560
- mathQuill.cmd("\\frac");
561
- if (shouldNavigateLeft) {
562
- mathQuill.keystroke("Left");
563
- }
564
- },
565
- LOG_B: mathQuill => {
566
- mathQuill.typedText("log_");
567
- mathQuill.keystroke("Right");
568
- mathQuill.typedText("(");
569
- mathQuill.keystroke("Left");
570
- mathQuill.keystroke("Left");
571
- },
572
- LOG_N: mathQuill => {
573
- mathQuill.write("log_{ }\\left(\\right)");
574
- mathQuill.keystroke("Left"); // into parentheses
575
- mathQuill.keystroke("Left"); // out of parentheses
576
- mathQuill.keystroke("Left"); // into index
577
- },
578
-
579
- NTHROOT3: mathQuill => {
580
- mathQuill.typedText("nthroot3");
581
- mathQuill.keystroke("Right");
582
- },
583
- POW: mathQuill => {
584
- const contents = mathQuill.latex();
585
- mathQuill.typedText("^");
586
433
 
587
- // If the input hasn't changed (for example, if we're
588
- // attempting to add an exponent on an empty input or an empty
589
- // denominator), insert our own "a^b"
590
- if (mathQuill.latex() === contents) {
591
- mathQuill.typedText("a^b");
592
- }
593
- },
594
- // These need to be overwritten by the consumer
595
- // if they're going to be used
596
- FRAC: () => {},
597
- RIGHT: () => {},
598
- LEFT: () => {},
599
- BACKSPACE: () => {},
600
- DISMISS: () => {},
601
- JUMP_OUT_PARENTHESES: () => {},
602
- JUMP_OUT_EXPONENT: () => {},
603
- JUMP_OUT_BASE: () => {},
604
- JUMP_INTO_NUMERATOR: () => {},
605
- JUMP_OUT_NUMERATOR: () => {},
606
- JUMP_OUT_DENOMINATOR: () => {},
607
- NOOP: () => {},
608
- MANY: () => {},
609
- NUM_0: buildGenericCallback("0"),
610
- NUM_1: buildGenericCallback("1"),
611
- NUM_2: buildGenericCallback("2"),
612
- NUM_3: buildGenericCallback("3"),
613
- NUM_4: buildGenericCallback("4"),
614
- NUM_5: buildGenericCallback("5"),
615
- NUM_6: buildGenericCallback("6"),
616
- NUM_7: buildGenericCallback("7"),
617
- NUM_8: buildGenericCallback("8"),
618
- NUM_9: buildGenericCallback("9"),
619
- a: buildGenericCallback("a"),
620
- b: buildGenericCallback("b"),
621
- c: buildGenericCallback("c"),
622
- d: buildGenericCallback("d"),
623
- e: buildGenericCallback("e"),
624
- f: buildGenericCallback("f"),
625
- g: buildGenericCallback("g"),
626
- h: buildGenericCallback("h"),
627
- i: buildGenericCallback("i"),
628
- j: buildGenericCallback("j"),
629
- k: buildGenericCallback("k"),
630
- l: buildGenericCallback("l"),
631
- m: buildGenericCallback("m"),
632
- n: buildGenericCallback("n"),
633
- o: buildGenericCallback("o"),
634
- p: buildGenericCallback("p"),
635
- q: buildGenericCallback("q"),
636
- r: buildGenericCallback("r"),
637
- s: buildGenericCallback("s"),
638
- t: buildGenericCallback("t"),
639
- u: buildGenericCallback("u"),
640
- v: buildGenericCallback("v"),
641
- w: buildGenericCallback("w"),
642
- x: buildGenericCallback("x"),
643
- y: buildGenericCallback("y"),
644
- z: buildGenericCallback("z"),
645
- A: buildGenericCallback("A"),
646
- B: buildGenericCallback("B"),
647
- C: buildGenericCallback("C"),
648
- D: buildGenericCallback("D"),
649
- E: buildGenericCallback("E"),
650
- F: buildGenericCallback("F"),
651
- G: buildGenericCallback("G"),
652
- H: buildGenericCallback("H"),
653
- I: buildGenericCallback("I"),
654
- J: buildGenericCallback("J"),
655
- K: buildGenericCallback("K"),
656
- L: buildGenericCallback("L"),
657
- M: buildGenericCallback("M"),
658
- N: buildGenericCallback("N"),
659
- O: buildGenericCallback("O"),
660
- P: buildGenericCallback("P"),
661
- Q: buildGenericCallback("Q"),
662
- R: buildGenericCallback("R"),
663
- S: buildGenericCallback("S"),
664
- T: buildGenericCallback("T"),
665
- U: buildGenericCallback("U"),
666
- V: buildGenericCallback("V"),
667
- W: buildGenericCallback("W"),
668
- X: buildGenericCallback("X"),
669
- Y: buildGenericCallback("Y"),
670
- Z: buildGenericCallback("Z")
671
- };
434
+ /**
435
+ * Creates a new [MathField](http://docs.mathquill.com/en/latest/Api_Methods/#mqmathfieldhtml_element-config)
436
+ * instance within the given `container`.
437
+ *
438
+ * An optional configuration callback can be provided to customize
439
+ * the created MathField. A default configuration is passed to this
440
+ * callback which can then be adjusted as needed. The configuration
441
+ * returned from this callback is used to create the MathField.
442
+ * This allows callers to do minimal configuration as only configs
443
+ * that vary from the default need to be provided.
444
+ */
445
+ function createMathField(container, configCallback) {
446
+ const baseConfig = createBaseConfig();
447
+ const config = configCallback ? configCallback(baseConfig) : baseConfig;
448
+ return mathQuillInstance.MathField(container, config);
449
+ }
672
450
 
673
451
  let MathFieldActionType = /*#__PURE__*/function (MathFieldActionType) {
674
452
  MathFieldActionType["WRITE"] = "write";
@@ -739,7 +517,7 @@ function isInsideLogIndex(cursor) {
739
517
  return false;
740
518
  }
741
519
  function isInsideEmptyNode(cursor) {
742
- return cursor[MQ.L] === MathFieldActionType.MQ_END && cursor[MQ.R] === MathFieldActionType.MQ_END;
520
+ return cursor[mathQuillInstance.L] === MathFieldActionType.MQ_END && cursor[mathQuillInstance.R] === MathFieldActionType.MQ_END;
743
521
  }
744
522
  function selectNode(node, cursor) {
745
523
  cursor.insLeftOf(node);
@@ -799,7 +577,7 @@ function maybeFindCommand(initialNode) {
799
577
  } else {
800
578
  break;
801
579
  }
802
- node = node[MQ.L];
580
+ node = node[mathQuillInstance.L];
803
581
  }
804
582
 
805
583
  // If we hit the start of a command, then grab the rest of it by
@@ -807,7 +585,7 @@ function maybeFindCommand(initialNode) {
807
585
  // with its terminal node.
808
586
  if (startNode) {
809
587
  // Next, iterate from the start to the right.
810
- node = initialNode[MQ.R];
588
+ node = initialNode[mathQuillInstance.R];
811
589
  while (node !== 0) {
812
590
  const ctrlSeq = node.ctrlSeq.trim();
813
591
  if (commandCharRegex.test(ctrlSeq)) {
@@ -820,7 +598,7 @@ function maybeFindCommand(initialNode) {
820
598
  endNode = node;
821
599
  break;
822
600
  }
823
- node = node[MQ.R];
601
+ node = node[mathQuillInstance.R];
824
602
  }
825
603
  if (validCommands.includes(name)) {
826
604
  return {
@@ -846,18 +624,18 @@ function maybeFindCommand(initialNode) {
846
624
  * name (`name`) of the command
847
625
  */
848
626
  function maybeFindCommandBeforeParens(leftParenNode) {
849
- return maybeFindCommand(leftParenNode[MQ.L]);
627
+ return maybeFindCommand(leftParenNode[mathQuillInstance.L]);
850
628
  }
851
629
  function contextForCursor(cursor) {
852
630
  // First, try to find any fraction to the right, unimpeded.
853
631
  let visitor = cursor;
854
- while (visitor[MQ.R] !== MathFieldActionType.MQ_END) {
855
- if (isFraction(visitor[MQ.R])) {
632
+ while (visitor[mathQuillInstance.R] !== MathFieldActionType.MQ_END) {
633
+ if (isFraction(visitor[mathQuillInstance.R])) {
856
634
  return CursorContext.BEFORE_FRACTION;
857
- } else if (!isLeaf(visitor[MQ.R])) {
635
+ } else if (!isLeaf(visitor[mathQuillInstance.R])) {
858
636
  break;
859
637
  }
860
- visitor = visitor[MQ.R];
638
+ visitor = visitor[mathQuillInstance.R];
861
639
  }
862
640
 
863
641
  // If that didn't work, check if the parent or grandparent is a special
@@ -877,57 +655,8 @@ function contextForCursor(cursor) {
877
655
  }
878
656
  }
879
657
 
880
- function handleLeftArrow(mathField, cursor) {
881
- // If we're inside a function, and just after the left parentheses, we
882
- // need to skip the entire function name, rather than move the cursor
883
- // inside of it. For example, when hitting left from within the
884
- // parentheses in `cos()`, we want to place the cursor to the left of
885
- // the entire expression, rather than between the `s` and the left
886
- // parenthesis.
887
- // From the cursor's perspective, this requires that our left node is
888
- // the ActionType.MQ_END node, that our grandparent is the left parenthesis, and
889
- // the nodes to the left of our grandparent comprise a valid function
890
- // name.
891
- if (cursor[MQ.L] === MathFieldActionType.MQ_END) {
892
- const parent = cursor.parent;
893
- const grandparent = parent.parent;
894
- if (grandparent.ctrlSeq === "\\left(") {
895
- const command = maybeFindCommandBeforeParens(grandparent);
896
- if (command) {
897
- cursor.insLeftOf(command.startNode);
898
- return;
899
- }
900
- }
901
- }
902
-
903
- // Otherwise, we default to the standard MathQull left behavior.
904
- mathField.keystroke("Left");
905
- }
906
- function handleRightArrow(mathField, cursor) {
907
- const command = maybeFindCommand(cursor[MQ.R]);
908
- if (command) {
909
- // Similarly, if a function is to our right, then we need to place
910
- // the cursor at the start of its parenthetical content, which is
911
- // done by putting it to the left of ites parentheses and then
912
- // moving right once.
913
- cursor.insLeftOf(command.endNode);
914
- mathField.keystroke("Right");
915
- } else {
916
- // Otherwise, we default to the standard MathQull right behavior.
917
- mathField.keystroke("Right");
918
- }
919
- }
920
- function handleArrow(mathField, key) {
921
- const cursor = getCursor(mathField);
922
- if (key === "LEFT") {
923
- handleLeftArrow(mathField, cursor);
924
- } else if (key === "RIGHT") {
925
- handleRightArrow(mathField, cursor);
926
- }
927
- }
928
-
929
658
  function handleBackspaceInNthRoot(mathField, cursor) {
930
- const isAtLeftEnd = cursor[MQ.L] === MathFieldActionType.MQ_END;
659
+ const isAtLeftEnd = cursor[mathQuillInstance.L] === MathFieldActionType.MQ_END;
931
660
  const isRootEmpty = isInsideEmptyNode(cursor.parent.parent.blocks[0].ends);
932
661
  if (isAtLeftEnd) {
933
662
  selectNode(cursor.parent.parent, cursor);
@@ -946,7 +675,7 @@ function handleBackspaceInRootIndex(mathField, cursor) {
946
675
 
947
676
  const grandparent = cursor.parent.parent;
948
677
  const latex = grandparent.latex();
949
- const reinsertionPoint = grandparent[MQ.L];
678
+ const reinsertionPoint = grandparent[mathQuillInstance.L];
950
679
  selectNode(grandparent, cursor);
951
680
  const rootIsEmpty = grandparent.blocks[1].jQ.text() === "";
952
681
  if (rootIsEmpty) {
@@ -965,13 +694,13 @@ function handleBackspaceInRootIndex(mathField, cursor) {
965
694
 
966
695
  // Adjust the cursor to be to the left the sqrt.
967
696
  if (reinsertionPoint === MathFieldActionType.MQ_END) {
968
- mathField.moveToDirEnd(MQ.L);
697
+ mathField.moveToDirEnd(mathQuillInstance.L);
969
698
  } else {
970
699
  cursor.insRightOf(reinsertionPoint);
971
700
  }
972
701
  }
973
702
  } else {
974
- if (cursor[MQ.L] !== MathFieldActionType.MQ_END) {
703
+ if (cursor[mathQuillInstance.L] !== MathFieldActionType.MQ_END) {
975
704
  // If the cursor is not at the leftmost position inside the
976
705
  // root's index, delete a character.
977
706
  mathField.keystroke("Backspace");
@@ -984,14 +713,14 @@ function handleBackspaceInLogIndex(mathField, cursor) {
984
713
  const command = maybeFindCommandBeforeParens(grandparent);
985
714
  cursor.insLeftOf(command === null || command === void 0 ? void 0 : command.startNode);
986
715
  cursor.startSelection();
987
- if (grandparent[MQ.R] !== MathFieldActionType.MQ_END) {
988
- cursor.insRightOf(grandparent[MQ.R]);
716
+ if (grandparent[mathQuillInstance.R] !== MathFieldActionType.MQ_END) {
717
+ cursor.insRightOf(grandparent[mathQuillInstance.R]);
989
718
  } else {
990
719
  cursor.insRightOf(grandparent);
991
720
  }
992
721
  cursor.select();
993
722
  cursor.endSelection();
994
- const isLogBodyEmpty = grandparent[MQ.R].contentjQ.text() === "";
723
+ const isLogBodyEmpty = grandparent[mathQuillInstance.R].contentjQ.text() === "";
995
724
  if (isLogBodyEmpty) {
996
725
  // If there's no content inside the log's parens then delete the
997
726
  // whole thing.
@@ -1010,8 +739,8 @@ function handleBackspaceOutsideParens(cursor) {
1010
739
  // (x+1)| => |(x+1)|
1011
740
  // \log(x+1)| => |\log(x+1)|
1012
741
 
1013
- const leftNode = cursor[MQ.L];
1014
- const rightNode = cursor[MQ.R];
742
+ const leftNode = cursor[mathQuillInstance.L];
743
+ const rightNode = cursor[mathQuillInstance.R];
1015
744
  const command = maybeFindCommandBeforeParens(leftNode);
1016
745
  if (command && command.startNode) {
1017
746
  // There's a command before the parens so we select it as well as
@@ -1057,7 +786,7 @@ function handleBackspaceInsideParens(mathField, cursor) {
1057
786
  // - \log(|x+1) => |\log(x+1)|
1058
787
  // - \log(|) => |
1059
788
 
1060
- if (cursor[MQ.L] !== MathFieldActionType.MQ_END) {
789
+ if (cursor[mathQuillInstance.L] !== MathFieldActionType.MQ_END) {
1061
790
  // This command contains math and there's some math to
1062
791
  // the left of the cursor that we should delete normally
1063
792
  // before doing anything special.
@@ -1070,12 +799,12 @@ function handleBackspaceInsideParens(mathField, cursor) {
1070
799
  // has a subscript as is the case in log_n then move the cursor into
1071
800
  // the subscript, e.g. \log_{5}(|x+1) => \log_{5|}(x+1)
1072
801
 
1073
- if (grandparent[MQ.L].sub) {
802
+ if (grandparent[mathQuillInstance.L].sub) {
1074
803
  // if there is a subscript
1075
- if (grandparent[MQ.L].sub.jQ.text()) {
804
+ if (grandparent[mathQuillInstance.L].sub.jQ.text()) {
1076
805
  // and it contains text
1077
806
  // move the cursor to the right end of the subscript
1078
- cursor.insAtRightEnd(grandparent[MQ.L].sub);
807
+ cursor.insAtRightEnd(grandparent[mathQuillInstance.L].sub);
1079
808
  return;
1080
809
  }
1081
810
  }
@@ -1113,7 +842,7 @@ function handleBackspace(mathField) {
1113
842
  if (!cursor.selection) {
1114
843
  const parent = cursor.parent;
1115
844
  const grandparent = parent.parent;
1116
- const leftNode = cursor[MQ.L];
845
+ const leftNode = cursor[mathQuillInstance.L];
1117
846
  if (isFraction(leftNode)) {
1118
847
  selectNode(leftNode, cursor);
1119
848
  } else if (isSquareRoot(leftNode)) {
@@ -1140,6 +869,133 @@ function handleBackspace(mathField) {
1140
869
  }
1141
870
  }
1142
871
 
872
+ /**
873
+ * Constants that are shared between multiple files.
874
+ */
875
+
876
+ let KeypadType = /*#__PURE__*/function (KeypadType) {
877
+ KeypadType["FRACTION"] = "FRACTION";
878
+ KeypadType["EXPRESSION"] = "EXPRESSION";
879
+ return KeypadType;
880
+ }({});
881
+ const KeyTypes = ["EMPTY",
882
+ // For numerals, variables, and any other characters that themselves
883
+ // compose 'values'.
884
+ "VALUE",
885
+ // For buttons that insert or adjust math in an input.
886
+ "OPERATOR",
887
+ // For buttons that move the cursor in an input (including via
888
+ // deletion).
889
+ "INPUT_NAVIGATION",
890
+ // For buttons that modify the broader keypad state (e.g., by changing
891
+ // the visible pane).
892
+ "KEYPAD_NAVIGATION",
893
+ // For buttons that house multiple buttons and have no action
894
+ // themselves.
895
+ "MANY",
896
+ // For the echo animation that appears on press.
897
+ "ECHO"];
898
+ let DeviceOrientation = /*#__PURE__*/function (DeviceOrientation) {
899
+ DeviceOrientation["LANDSCAPE"] = "LANDSCAPE";
900
+ DeviceOrientation["PORTRAIT"] = "PORTRAIT";
901
+ return DeviceOrientation;
902
+ }({});
903
+ let DeviceType = /*#__PURE__*/function (DeviceType) {
904
+ DeviceType["PHONE"] = "PHONE";
905
+ DeviceType["TABLET"] = "TABLET";
906
+ return DeviceType;
907
+ }({});
908
+ let LayoutMode = /*#__PURE__*/function (LayoutMode) {
909
+ LayoutMode["FULLSCREEN"] = "FULLSCREEN";
910
+ LayoutMode["COMPACT"] = "COMPACT";
911
+ return LayoutMode;
912
+ }({});
913
+ let BorderDirection = /*#__PURE__*/function (BorderDirection) {
914
+ BorderDirection["LEFT"] = "LEFT";
915
+ BorderDirection["BOTTOM"] = "BOTTOM";
916
+ return BorderDirection;
917
+ }({});
918
+ const BorderStyles = {
919
+ LEFT: [BorderDirection.LEFT],
920
+ BOTTOM: [BorderDirection.BOTTOM],
921
+ ALL: [BorderDirection.LEFT, BorderDirection.BOTTOM],
922
+ NONE: []
923
+ };
924
+ let IconType = /*#__PURE__*/function (IconType) {
925
+ IconType["MATH"] = "MATH";
926
+ IconType["SVG"] = "SVG";
927
+ IconType["TEXT"] = "TEXT";
928
+ return IconType;
929
+ }({});
930
+ let DecimalSeparator = /*#__PURE__*/function (DecimalSeparator) {
931
+ DecimalSeparator["COMMA"] = "COMMA";
932
+ DecimalSeparator["PERIOD"] = "PERIOD";
933
+ return DecimalSeparator;
934
+ }({});
935
+ let EchoAnimationType = /*#__PURE__*/function (EchoAnimationType) {
936
+ EchoAnimationType["SLIDE_AND_FADE"] = "SLIDE_AND_FADE";
937
+ EchoAnimationType["FADE_ONLY"] = "FADE_ONLY";
938
+ EchoAnimationType["LONG_FADE_ONLY"] = "LONG_FADE_ONLY";
939
+ return EchoAnimationType;
940
+ }({});
941
+
942
+ // NOTES(kevinb):
943
+ // - In order to get the correct decimal separator for the current locale,
944
+ // the locale must bet set using `setLocale(kaLocale)` which can be
945
+ // imported from wonder-blocks-i18n.
946
+ // - Some languages/locales use different decimal separators than the ones
947
+ // listed here. Much of the Arab world uses U+066C.
948
+ const decimalSeparator = i18n.getDecimalSeparator() === "," ? DecimalSeparator.COMMA : DecimalSeparator.PERIOD;
949
+
950
+ function handleLeftArrow(mathField, cursor) {
951
+ // If we're inside a function, and just after the left parentheses, we
952
+ // need to skip the entire function name, rather than move the cursor
953
+ // inside of it. For example, when hitting left from within the
954
+ // parentheses in `cos()`, we want to place the cursor to the left of
955
+ // the entire expression, rather than between the `s` and the left
956
+ // parenthesis.
957
+ // From the cursor's perspective, this requires that our left node is
958
+ // the ActionType.MQ_END node, that our grandparent is the left parenthesis, and
959
+ // the nodes to the left of our grandparent comprise a valid function
960
+ // name.
961
+ if (cursor[mathQuillInstance.L] === MathFieldActionType.MQ_END) {
962
+ const parent = cursor.parent;
963
+ const grandparent = parent.parent;
964
+ if (grandparent.ctrlSeq === "\\left(") {
965
+ const command = maybeFindCommandBeforeParens(grandparent);
966
+ if (command) {
967
+ cursor.insLeftOf(command.startNode);
968
+ return;
969
+ }
970
+ }
971
+ }
972
+
973
+ // Otherwise, we default to the standard MathQull left behavior.
974
+ mathField.keystroke("Left");
975
+ }
976
+ function handleRightArrow(mathField, cursor) {
977
+ const command = maybeFindCommand(cursor[mathQuillInstance.R]);
978
+ if (command) {
979
+ // Similarly, if a function is to our right, then we need to place
980
+ // the cursor at the start of its parenthetical content, which is
981
+ // done by putting it to the left of ites parentheses and then
982
+ // moving right once.
983
+ cursor.insLeftOf(command.endNode);
984
+ mathField.keystroke("Right");
985
+ } else {
986
+ // Otherwise, we default to the standard MathQull right behavior.
987
+ mathField.keystroke("Right");
988
+ }
989
+ }
990
+ function handleArrow(mathField, key) {
991
+ const cursor = getCursor(mathField);
992
+ if (key === "LEFT") {
993
+ handleLeftArrow(mathField, cursor);
994
+ } else if (key === "RIGHT") {
995
+ handleRightArrow(mathField, cursor);
996
+ }
997
+ }
998
+
1143
999
  const ArithmeticOperators = ["+", "-", "\\cdot", "\\times", "\\div"];
1144
1000
  const EqualityOperators = ["=", "\\neq", "<", "\\leq", ">", "\\geq"];
1145
1001
  function handleExponent(mathField, key) {
@@ -1148,7 +1004,7 @@ function handleExponent(mathField, key) {
1148
1004
  // knowingly cannot be raised to a power), add an empty set of
1149
1005
  // parentheses and apply the exponent to that.
1150
1006
  const invalidPrefixes = [...ArithmeticOperators, ...EqualityOperators];
1151
- const precedingNode = cursor[MQ.L];
1007
+ const precedingNode = cursor[mathQuillInstance.L];
1152
1008
  const shouldPrefixWithParens = precedingNode === MathFieldActionType.MQ_END || invalidPrefixes.includes(precedingNode.ctrlSeq.trim());
1153
1009
  if (shouldPrefixWithParens) {
1154
1010
  mathField.write("\\left(\\right)");
@@ -1214,11 +1070,11 @@ function handleJumpOut(mathField, key) {
1214
1070
  // Find the nearest fraction to the right of the cursor.
1215
1071
  let fractionNode;
1216
1072
  let visitor = cursor;
1217
- while (visitor[MQ.R] !== MathFieldActionType.MQ_END) {
1218
- if (isFraction(visitor[MQ.R])) {
1219
- fractionNode = visitor[MQ.R];
1073
+ while (visitor[mathQuillInstance.R] !== MathFieldActionType.MQ_END) {
1074
+ if (isFraction(visitor[mathQuillInstance.R])) {
1075
+ fractionNode = visitor[mathQuillInstance.R];
1220
1076
  }
1221
- visitor = visitor[MQ.R];
1077
+ visitor = visitor[mathQuillInstance.R];
1222
1078
  }
1223
1079
 
1224
1080
  // Jump into it!
@@ -1247,7 +1103,7 @@ function handleJumpOut(mathField, key) {
1247
1103
  // Navigate right once more, if we're right before parens. This
1248
1104
  // is to handle the standard case in which the subscript is the
1249
1105
  // base of a custom log.
1250
- if (isParens(cursor[MQ.R])) {
1106
+ if (isParens(cursor[mathQuillInstance.R])) {
1251
1107
  mathField.keystroke("Right");
1252
1108
  }
1253
1109
  break;
@@ -1260,26 +1116,46 @@ function handleJumpOut(mathField, key) {
1260
1116
  }
1261
1117
  }
1262
1118
 
1119
+ var ActionType = /*#__PURE__*/function (ActionType) {
1120
+ ActionType["WRITE"] = "write";
1121
+ ActionType["CMD"] = "cmd";
1122
+ ActionType["KEYSTROKE"] = "keystroke";
1123
+ ActionType[ActionType["MQ_END"] = 0] = "MQ_END";
1124
+ return ActionType;
1125
+ }(ActionType || {});
1126
+ const decimalSymbol = decimalSeparator === DecimalSeparator.COMMA ? "," : ".";
1127
+ function buildGenericCallback(str) {
1128
+ let type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ActionType.WRITE;
1129
+ return function (mathQuill) {
1130
+ switch (type) {
1131
+ case ActionType.WRITE:
1132
+ {
1133
+ mathQuill.write(str);
1134
+ return;
1135
+ }
1136
+ case ActionType.CMD:
1137
+ {
1138
+ mathQuill.cmd(str);
1139
+ return;
1140
+ }
1141
+ case ActionType.KEYSTROKE:
1142
+ {
1143
+ mathQuill.keystroke(str);
1144
+ return;
1145
+ }
1146
+ }
1147
+ };
1148
+ }
1263
1149
  function buildNormalFunctionCallback(command) {
1264
1150
  return function (mathField) {
1265
1151
  mathField.write("\\".concat(command, "\\left(\\right)"));
1266
1152
  mathField.keystroke("Left");
1267
1153
  };
1268
1154
  }
1269
- const customKeyTranslator = {
1270
- ...keyToMathquillMap,
1271
- // note(Matthew): in all likelihood, this should be moved
1272
- // to the shared key2MathQuill translator. During this refactor
1273
- // I tried to keep logic the same while deduplicating code.
1274
- // Perseus' Expression MathInput treats this stuff differently
1275
- // (or doesn't do anything with them at all), so I kept it that way
1276
- BACKSPACE: handleBackspace,
1155
+ const keyToMathquillMap = {
1277
1156
  EXP: handleExponent,
1278
1157
  EXP_2: handleExponent,
1279
1158
  EXP_3: handleExponent,
1280
- FRAC: mathQuill => {
1281
- mathQuill.cmd("\\frac");
1282
- },
1283
1159
  JUMP_OUT_PARENTHESES: handleJumpOut,
1284
1160
  JUMP_OUT_EXPONENT: handleJumpOut,
1285
1161
  JUMP_OUT_BASE: handleJumpOut,
@@ -1292,7 +1168,158 @@ const customKeyTranslator = {
1292
1168
  LN: buildNormalFunctionCallback("ln"),
1293
1169
  SIN: buildNormalFunctionCallback("sin"),
1294
1170
  COS: buildNormalFunctionCallback("cos"),
1295
- TAN: buildNormalFunctionCallback("tan")
1171
+ TAN: buildNormalFunctionCallback("tan"),
1172
+ CDOT: buildGenericCallback("\\cdot"),
1173
+ DECIMAL: buildGenericCallback(decimalSymbol),
1174
+ DIVIDE: buildGenericCallback("\\div"),
1175
+ EQUAL: buildGenericCallback("="),
1176
+ GEQ: buildGenericCallback("\\geq"),
1177
+ GT: buildGenericCallback(">"),
1178
+ LEQ: buildGenericCallback("\\leq"),
1179
+ LT: buildGenericCallback("<"),
1180
+ MINUS: buildGenericCallback("-"),
1181
+ NEGATIVE: buildGenericCallback("-"),
1182
+ NEQ: buildGenericCallback("\\neq"),
1183
+ PERCENT: buildGenericCallback("%"),
1184
+ PERIOD: buildGenericCallback("."),
1185
+ PLUS: buildGenericCallback("+"),
1186
+ TIMES: buildGenericCallback("\\times"),
1187
+ // The `FRAC_EXCLUSIVE` variant is handled manually, since we may need to do
1188
+ // some additional navigation depending on the cursor position.
1189
+ FRAC_INCLUSIVE: buildGenericCallback("/", ActionType.CMD),
1190
+ FRAC: buildGenericCallback("\\frac", ActionType.CMD),
1191
+ LEFT_PAREN: buildGenericCallback("(", ActionType.CMD),
1192
+ RIGHT_PAREN: buildGenericCallback(")", ActionType.CMD),
1193
+ SQRT: buildGenericCallback("sqrt", ActionType.CMD),
1194
+ PHI: buildGenericCallback("\\phi", ActionType.CMD),
1195
+ PI: buildGenericCallback("pi", ActionType.CMD),
1196
+ THETA: buildGenericCallback("theta", ActionType.CMD),
1197
+ RADICAL: buildGenericCallback("nthroot", ActionType.CMD),
1198
+ BACKSPACE: buildGenericCallback("Backspace", ActionType.KEYSTROKE),
1199
+ UP: buildGenericCallback("Up", ActionType.KEYSTROKE),
1200
+ DOWN: buildGenericCallback("Down", ActionType.KEYSTROKE),
1201
+ CUBE_ROOT: mathQuill => {
1202
+ mathQuill.write("\\sqrt[3]{}");
1203
+ mathQuill.keystroke("Left"); // under the root
1204
+ },
1205
+
1206
+ FRAC_EXCLUSIVE: mathQuill => {
1207
+ const cursor = mathQuill.__controller.cursor;
1208
+ // If there's nothing to the left of the cursor, then we want to
1209
+ // leave the cursor to the left of the fraction after creating it.
1210
+ const shouldNavigateLeft = cursor[mathQuillInstance.L] === ActionType.MQ_END;
1211
+ mathQuill.cmd("\\frac");
1212
+ if (shouldNavigateLeft) {
1213
+ mathQuill.keystroke("Left");
1214
+ }
1215
+ },
1216
+ LOG_B: mathQuill => {
1217
+ mathQuill.typedText("log_");
1218
+ mathQuill.keystroke("Right");
1219
+ mathQuill.typedText("(");
1220
+ mathQuill.keystroke("Left");
1221
+ mathQuill.keystroke("Left");
1222
+ },
1223
+ LOG_N: mathQuill => {
1224
+ mathQuill.write("log_{ }\\left(\\right)");
1225
+ mathQuill.keystroke("Left"); // into parentheses
1226
+ mathQuill.keystroke("Left"); // out of parentheses
1227
+ mathQuill.keystroke("Left"); // into index
1228
+ },
1229
+
1230
+ NTHROOT3: mathQuill => {
1231
+ mathQuill.typedText("nthroot3");
1232
+ mathQuill.keystroke("Right");
1233
+ },
1234
+ POW: mathQuill => {
1235
+ const contents = mathQuill.latex();
1236
+ mathQuill.typedText("^");
1237
+
1238
+ // If the input hasn't changed (for example, if we're
1239
+ // attempting to add an exponent on an empty input or an empty
1240
+ // denominator), insert our own "a^b"
1241
+ if (mathQuill.latex() === contents) {
1242
+ mathQuill.typedText("a^b");
1243
+ }
1244
+ },
1245
+ // These need to be overwritten by the consumer
1246
+ // if they're going to be used
1247
+ DISMISS: () => {},
1248
+ NOOP: () => {},
1249
+ MANY: () => {},
1250
+ NUM_0: buildGenericCallback("0"),
1251
+ NUM_1: buildGenericCallback("1"),
1252
+ NUM_2: buildGenericCallback("2"),
1253
+ NUM_3: buildGenericCallback("3"),
1254
+ NUM_4: buildGenericCallback("4"),
1255
+ NUM_5: buildGenericCallback("5"),
1256
+ NUM_6: buildGenericCallback("6"),
1257
+ NUM_7: buildGenericCallback("7"),
1258
+ NUM_8: buildGenericCallback("8"),
1259
+ NUM_9: buildGenericCallback("9"),
1260
+ a: buildGenericCallback("a"),
1261
+ b: buildGenericCallback("b"),
1262
+ c: buildGenericCallback("c"),
1263
+ d: buildGenericCallback("d"),
1264
+ e: buildGenericCallback("e"),
1265
+ f: buildGenericCallback("f"),
1266
+ g: buildGenericCallback("g"),
1267
+ h: buildGenericCallback("h"),
1268
+ i: buildGenericCallback("i"),
1269
+ j: buildGenericCallback("j"),
1270
+ k: buildGenericCallback("k"),
1271
+ l: buildGenericCallback("l"),
1272
+ m: buildGenericCallback("m"),
1273
+ n: buildGenericCallback("n"),
1274
+ o: buildGenericCallback("o"),
1275
+ p: buildGenericCallback("p"),
1276
+ q: buildGenericCallback("q"),
1277
+ r: buildGenericCallback("r"),
1278
+ s: buildGenericCallback("s"),
1279
+ t: buildGenericCallback("t"),
1280
+ u: buildGenericCallback("u"),
1281
+ v: buildGenericCallback("v"),
1282
+ w: buildGenericCallback("w"),
1283
+ x: buildGenericCallback("x"),
1284
+ y: buildGenericCallback("y"),
1285
+ z: buildGenericCallback("z"),
1286
+ A: buildGenericCallback("A"),
1287
+ B: buildGenericCallback("B"),
1288
+ C: buildGenericCallback("C"),
1289
+ D: buildGenericCallback("D"),
1290
+ E: buildGenericCallback("E"),
1291
+ F: buildGenericCallback("F"),
1292
+ G: buildGenericCallback("G"),
1293
+ H: buildGenericCallback("H"),
1294
+ I: buildGenericCallback("I"),
1295
+ J: buildGenericCallback("J"),
1296
+ K: buildGenericCallback("K"),
1297
+ L: buildGenericCallback("L"),
1298
+ M: buildGenericCallback("M"),
1299
+ N: buildGenericCallback("N"),
1300
+ O: buildGenericCallback("O"),
1301
+ P: buildGenericCallback("P"),
1302
+ Q: buildGenericCallback("Q"),
1303
+ R: buildGenericCallback("R"),
1304
+ S: buildGenericCallback("S"),
1305
+ T: buildGenericCallback("T"),
1306
+ U: buildGenericCallback("U"),
1307
+ V: buildGenericCallback("V"),
1308
+ W: buildGenericCallback("W"),
1309
+ X: buildGenericCallback("X"),
1310
+ Y: buildGenericCallback("Y"),
1311
+ Z: buildGenericCallback("Z")
1312
+ };
1313
+
1314
+ const mobileKeyTranslator = {
1315
+ ...keyToMathquillMap,
1316
+ // note(Matthew): our mobile backspace logic is really complicated
1317
+ // and for some reason doesn't really work in the desktop experience.
1318
+ // So we default to the basic backspace functionality in the
1319
+ // key translator and overwrite it with the complicated logic here
1320
+ // until we can unify the experiences (if we even want to).
1321
+ // https://khanacademy.atlassian.net/browse/LC-906
1322
+ BACKSPACE: handleBackspace
1296
1323
  };
1297
1324
 
1298
1325
  /**
@@ -1301,18 +1328,20 @@ const customKeyTranslator = {
1301
1328
  * from MathQuill changes.
1302
1329
  */
1303
1330
  class MathWrapper {
1304
- // MathQuill input
1331
+ // MathQuill MathField input
1305
1332
 
1306
1333
  constructor(element) {
1307
- let callbacks = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
1334
+ let callbacks = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1308
1335
  _defineProperty(this, "mathField", void 0);
1309
1336
  _defineProperty(this, "callbacks", void 0);
1310
- this.mathField = MQ.MathField(element, {
1311
- // use a span instead of a textarea so that we don't bring up the
1312
- // native keyboard on mobile when selecting the input
1313
- substituteTextarea: function () {
1314
- return document.createElement("span");
1315
- }
1337
+ this.mathField = createMathField(element, () => {
1338
+ return {
1339
+ // use a span instead of a textarea so that we don't bring up the
1340
+ // native keyboard on mobile when selecting the input
1341
+ substituteTextarea: function () {
1342
+ return document.createElement("span");
1343
+ }
1344
+ };
1316
1345
  });
1317
1346
  this.callbacks = callbacks;
1318
1347
  }
@@ -1342,7 +1371,7 @@ class MathWrapper {
1342
1371
  */
1343
1372
  pressKey(key) {
1344
1373
  const cursor = this.getCursor();
1345
- const translator = customKeyTranslator[key];
1374
+ const translator = mobileKeyTranslator[key];
1346
1375
  if (translator) {
1347
1376
  translator(this.mathField, key);
1348
1377
  }
@@ -1390,7 +1419,7 @@ class MathWrapper {
1390
1419
  // Unless that would leave us mid-command, in which case, we
1391
1420
  // need to adjust and place the cursor inside the parens
1392
1421
  // following the command.
1393
- const command = maybeFindCommand(cursor[MQ.L]);
1422
+ const command = maybeFindCommand(cursor[mathQuillInstance.L]);
1394
1423
  if (command && command.endNode) {
1395
1424
  // NOTE(charlie): endNode should definitely be \left(.
1396
1425
  cursor.insLeftOf(command.endNode);
@@ -1961,7 +1990,7 @@ class MathInput extends React__namespace.Component {
1961
1990
  }
1962
1991
  componentDidMount() {
1963
1992
  this._isMounted = true;
1964
- this.mathField = new MathWrapper(this._mathContainer, {}, {
1993
+ this.mathField = new MathWrapper(this._mathContainer, {
1965
1994
  onCursorMove: cursor => {
1966
1995
  // TODO(charlie): It's not great that there is so much coupling
1967
1996
  // between this keypad and the input behavior. We should wrap
@@ -8363,7 +8392,7 @@ const KeypadButton = _ref2 => {
8363
8392
  onPress: () => onClickKey(keyConfig.id),
8364
8393
  tintColor: tintColor,
8365
8394
  style: style,
8366
- ariaLabel: keyConfig.id
8395
+ ariaLabel: keyConfig.ariaLabel
8367
8396
  }, /*#__PURE__*/React__namespace.createElement(ButtonAsset, {
8368
8397
  id: keyConfig.id
8369
8398
  }));
@@ -8793,6 +8822,8 @@ exports.Keypad = Keypad;
8793
8822
  exports.KeypadInput = MathInput;
8794
8823
  exports.KeypadType = KeypadType;
8795
8824
  exports.LegacyKeypad = ProvidedKeypad;
8825
+ exports.createMathField = createMathField;
8796
8826
  exports.keyTranslator = keyToMathquillMap;
8797
8827
  exports.keypadElementPropType = keypadElementPropType;
8828
+ exports.mathQuillInstance = mathQuillInstance;
8798
8829
  //# sourceMappingURL=index.js.map