@khanacademy/math-input 4.3.1 → 5.0.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 (42) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/components/input/math-wrapper.d.ts +2 -2
  3. package/dist/components/input/math-wrapper.js.flow +2 -4
  4. package/dist/components/input/mathquill-helpers.d.ts +1 -1
  5. package/dist/components/input/mathquill-helpers.js.flow +2 -2
  6. package/dist/components/input/mathquill-types.d.ts +270 -10
  7. package/dist/components/input/mathquill-types.js.flow +312 -10
  8. package/dist/components/keypad/index.d.ts +11 -1
  9. package/dist/components/keypad/index.js.flow +14 -1
  10. package/dist/components/keypad/shared-keys.d.ts +4 -0
  11. package/dist/components/keypad/shared-keys.js.flow +4 -0
  12. package/dist/components/tabbar/tabbar.d.ts +1 -0
  13. package/dist/components/tabbar/tabbar.js.flow +1 -0
  14. package/dist/components/tabbar/types.d.ts +1 -1
  15. package/dist/components/tabbar/types.js.flow +6 -1
  16. package/dist/es/index.js +173 -48
  17. package/dist/es/index.js.map +1 -1
  18. package/dist/index.js +173 -48
  19. package/dist/index.js.map +1 -1
  20. package/package.json +2 -1
  21. package/src/components/input/__tests__/mathquill-helpers.test.ts +105 -0
  22. package/src/components/input/math-input.tsx +1 -1
  23. package/src/components/input/math-wrapper.ts +6 -10
  24. package/src/components/input/mathquill-helpers.ts +8 -1
  25. package/src/components/input/mathquill-types.ts +308 -40
  26. package/src/components/key-handlers/__tests__/handle-jump-out.test.ts +94 -0
  27. package/src/components/key-handlers/handle-jump-out.ts +3 -2
  28. package/src/components/keypad/__tests__/keypad-v2-mathquill.test.tsx +42 -39
  29. package/src/components/keypad/__tests__/keypad.test.tsx +42 -0
  30. package/src/components/keypad/button-assets.tsx +34 -6
  31. package/src/components/keypad/index.tsx +25 -2
  32. package/src/components/keypad/keypad-mathquill.stories.tsx +19 -0
  33. package/src/components/keypad/keypad-pages/extras-page.tsx +1 -1
  34. package/src/components/keypad/keypad-pages/numbers-page.tsx +25 -16
  35. package/src/components/keypad/shared-keys.tsx +56 -8
  36. package/src/components/tabbar/__tests__/tabbar.test.tsx +54 -14
  37. package/src/components/tabbar/icons.tsx +34 -12
  38. package/src/components/tabbar/item.tsx +2 -0
  39. package/src/components/tabbar/tabbar.tsx +32 -12
  40. package/src/components/tabbar/types.ts +6 -1
  41. package/tsconfig-build.json +3 -1
  42. package/tsconfig-build.tsbuildinfo +1 -1
package/dist/es/index.js CHANGED
@@ -387,6 +387,12 @@ function createMathField(container, configCallback) {
387
387
  return mathQuillInstance.MathField(container, config);
388
388
  }
389
389
 
390
+ /**
391
+ * Editable math fields have all of the above methods in addition to
392
+ * the ones listed here.
393
+ * https://docs.mathquill.com/en/latest/Api_Methods/
394
+ */
395
+
390
396
  let MathFieldActionType = /*#__PURE__*/function (MathFieldActionType) {
391
397
  MathFieldActionType["WRITE"] = "write";
392
398
  MathFieldActionType["CMD"] = "cmd";
@@ -395,9 +401,11 @@ let MathFieldActionType = /*#__PURE__*/function (MathFieldActionType) {
395
401
  return MathFieldActionType;
396
402
  }({});
397
403
 
398
- // The MathQuill MathField Cursor
399
- // it's not part of the public API for MathQuill,
400
- // we reach into the internals to get it
404
+ /**
405
+ * The MathQuill MathField Cursor
406
+ * it's not part of the public API for MathQuill,
407
+ * we reach into the internals to get it
408
+ */
401
409
 
402
410
  const Numerals = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
403
411
  const GreekLetters = ["\\theta", "\\pi"];
@@ -565,8 +573,13 @@ function maybeFindCommand(initialNode) {
565
573
  function maybeFindCommandBeforeParens(leftParenNode) {
566
574
  return maybeFindCommand(leftParenNode[mathQuillInstance.L]);
567
575
  }
568
- function contextForCursor(cursor) {
576
+ function getCursorContext(mathField) {
577
+ if (!mathField) {
578
+ return CursorContext.NONE;
579
+ }
580
+
569
581
  // First, try to find any fraction to the right, unimpeded.
582
+ const cursor = getCursor(mathField);
570
583
  let visitor = cursor;
571
584
  while (visitor[mathQuillInstance.R] !== MathFieldActionType.MQ_END) {
572
585
  if (isFraction(visitor[mathQuillInstance.R])) {
@@ -988,7 +1001,7 @@ const KeysForJumpContext = {
988
1001
  */
989
1002
  function handleJumpOut(mathField, key) {
990
1003
  const cursor = getCursor(mathField);
991
- const context = contextForCursor(cursor);
1004
+ const context = getCursorContext(mathField);
992
1005
 
993
1006
  // Validate that the current cursor context matches the key's intent.
994
1007
  if (KeysForJumpContext[context] !== key) {
@@ -1004,6 +1017,7 @@ function handleJumpOut(mathField, key) {
1004
1017
  // Insert at the end of the parentheses, and then navigate right
1005
1018
  // once more to get 'beyond' the parentheses.
1006
1019
  cursor.insRightOf(cursor.parent.parent);
1020
+ mathField.keystroke("Right");
1007
1021
  break;
1008
1022
  case CursorContext.BEFORE_FRACTION:
1009
1023
  // Find the nearest fraction to the right of the cursor.
@@ -1323,7 +1337,7 @@ class MathWrapper {
1323
1337
  // on the MathField, as that handler isn't triggered on navigation
1324
1338
  // events.
1325
1339
  return {
1326
- context: this.contextForCursor(cursor)
1340
+ context: this.contextForCursor()
1327
1341
  };
1328
1342
  }
1329
1343
 
@@ -1364,7 +1378,7 @@ class MathWrapper {
1364
1378
  }
1365
1379
  if (this.callbacks.onCursorMove) {
1366
1380
  this.callbacks.onCursorMove({
1367
- context: this.contextForCursor(cursor)
1381
+ context: this.contextForCursor()
1368
1382
  });
1369
1383
  }
1370
1384
  }
@@ -1378,8 +1392,8 @@ class MathWrapper {
1378
1392
 
1379
1393
  // note(Matthew): extracted this logic to keep this file focused,
1380
1394
  // but it's part of the public MathWrapper API
1381
- contextForCursor(cursor) {
1382
- return contextForCursor(cursor);
1395
+ contextForCursor() {
1396
+ return getCursorContext(this.mathField);
1383
1397
  }
1384
1398
  getSelection() {
1385
1399
  return this.getCursor().selection;
@@ -1734,7 +1748,7 @@ class MathInput extends React.Component {
1734
1748
  }
1735
1749
  // In that event, we need to update the cursor context ourselves.
1736
1750
  this.props.keypadElement && this.props.keypadElement.setCursor({
1737
- context: this.mathField.contextForCursor(cursor)
1751
+ context: this.mathField.contextForCursor()
1738
1752
  });
1739
1753
  };
1740
1754
  this.handleTouchStart = e => {
@@ -4798,26 +4812,44 @@ const IconAsset = function IconAsset({
4798
4812
  case "Extras":
4799
4813
  {
4800
4814
  return /*#__PURE__*/React.createElement("svg", {
4815
+ xmlns: "http://www.w3.org/2000/svg",
4801
4816
  width: "32",
4802
4817
  height: "32",
4803
- viewBox: "0 0 32 32",
4804
4818
  fill: "none",
4805
- xmlns: "http://www.w3.org/2000/svg"
4819
+ viewBox: "0 0 32 32"
4806
4820
  }, /*#__PURE__*/React.createElement("g", {
4807
- clipPath: "url(#clip0_4011_87172)",
4808
- fillRule: "evenodd",
4809
- clipRule: "evenodd",
4810
- fill: tintColor
4821
+ clipPath: "url(#a)"
4811
4822
  }, /*#__PURE__*/React.createElement("path", {
4812
- d: "M6.96605 10.5663c.21528-.0308.38682-.0477.50829-.0477.56911 0 1.09298.1467 1.56707.4407.38228.2296.68532.5084.90301.838.09208-.1207.15248-.2002.18138-.2387l.0047-.0063.0052-.0059c.5949-.6753 1.2944-1.0278 2.093-1.0278.6647 0 1.2196.1954 1.6441.6014.4361.3871.6588.8746.6588 1.45 0 .513-.1499.9563-.4578 1.3166-.3.3693-.7089.552-1.2051.552-.3307 0-.6179-.097-.8437-.304-.2288-.2097-.3392-.4865-.3392-.8103 0-.3888.1066-.7297.3291-1.0101.1474-.1857.3402-.3379.5729-.4597-.1089-.0413-.2631-.0674-.4734-.0674-.1874 0-.3034.0147-.3645.0334-.5098.2175-.9018.667-1.1616 1.3887l-.0009.0025c-.0181.0482-.0814.2776-.1937.7113-.1103.4259-.2644 1.0348-.46245 1.827-.398 1.5767-.60776 2.4474-.63636 2.6333l-.00136.0089c-.04319.2159-.06489.4313-.06489.6465 0 .3246.09331.559.26143.7271.16975.1698.39759.2614.70433.2614.5767 0 1.1059-.2376 1.5927-.7383.4978-.5273.8301-1.1009 1.0032-1.7212l.0011-.0037c.0246-.0819.0521-.156.0846-.2154.0241-.0443.0711-.1194.1545-.1578.0615-.0338.1345-.0465.1905-.0535.0726-.0091.1619-.013.2648-.013.1528 0 .2937.0152.4034.0614.0569.024.1156.0605.1606.1174.0474.0598.0703.1308.0703.2041 0 .022-.0038.0459-.0052.0547-.0023.015-.0055.0337-.0094.0554-.008.0436-.0197.104-.035.1806l-.0027.0138c-.2705.9863-.8277 1.8422-1.6623 2.5666l-.0072.0063c-.746.5872-1.5429.8884-2.3868.8884-1.03863 0-1.85432-.4315-2.43176-1.277-.43549.5807-.97515.9834-1.61932 1.1981l-.00979.0033-.01007.0022c-.15865.0353-.37406.0505-.63768.0505-.93641 0-1.63679-.3356-2.04681-1.0359C3.08287 19.9196 3 19.5787 3 19.1987c0-.5006.1515-.9365.45958-1.2959.31283-.365.71906-.5499 1.2033-.5499.35729 0 .6622.0872.87689.2969.21557.2106.30597.5111.30597.8631 0 .3146-.07482.5975-.23217.8402-.15675.2419-.38726.4314-.67931.5735-.00496.0025-.01055.0055-.01678.0089.15188.0606.31779.0917.49969.0917.44797 0 .86602-.2744 1.24399-.9286l.00246-.0043c.06785-.111.17746-.4008.32772-.9017.14728-.4909.32737-1.1618.5404-2.0139l.0005-.002c.09122-.3497.19011-.7376.29665-1.1637.10644-.4258.18171-.7498.22648-.9736l.00249-.0124c.05541-.2078.09408-.3468.11359-.4088.07445-.404.10861-.6812.10861-.8425 0-.3287-.08814-.5649-.2437-.7325-.15265-.1644-.36917-.2561-.67631-.2561-.62654 0-1.16936.2409-1.63736.7372l-.00199.0022c-.47891.4934-.81198 1.0647-1.00116 1.7162-.0166.0733-.03697.141-.06317.1987-.02519.0554-.06558.1237-.13399.1693l-.01036.0069-.01113.0056c-.03837.0192-.07945.0259-.09978.0289-.02704.0041-.05815.0069-.09148.009-.06706.0042-.15565.0061-.26391.0061h-.40284l-.05858-.0586c-.10441-.1044-.19572-.2369-.19572-.3929v-.0147l.00216-.0146c.06726-.454.32204-1.0087.73818-1.656l.00145-.0022c.74101-1.1194 1.68544-1.7837 2.83334-1.9616l.00234-.0003zM20.9726 10.5186h10.0353c.2631 0 .5155.1045.7016.2906.1861.1861.2906.4384.2906.7016s-.1045.5156-.2906.7016c-.1861.1861-.4385.2907-.7016.2907h-2.705v6.138c0 .2272.0902.445.2508.6056.1606.1606.3784.2508.6056.2508.2271 0 .4449-.0902.6055-.2508.1606-.1606.2508-.3784.2508-.6056 0-.2631.1045-.5155.2906-.7016.1861-.1861.4385-.2906.7017-.2906.2631 0 .5155.1045.7016.2906.1861.1861.2906.4385.2906.7016 0 .7535-.2993 1.4761-.8321 2.0088-.5327.5328-1.2553.8321-2.0087.8321-.7535 0-1.4761-.2993-2.0088-.8321-.5328-.5327-.8321-1.2553-.8321-2.0088v-6.138h-3.2972v7.9867c0 .2631-.1046.5155-.2906.7016-.1861.1861-.4385.2906-.7017.2906-.2631 0-.5155-.1045-.7016-.2906-.1861-.1861-.2906-.4385-.2906-.7016v-7.9867h-.0641c-.5773 0-1.131.2293-1.5392.6375-.4083.4083-.6376.9619-.6376 1.5393 0 .2631-.1045.5155-.2906.7016-.1861.1861-.4385.2906-.7017.2906-.2631 0-.5155-.1045-.7016-.2906-.1861-.1861-.2906-.4385-.2906-.7016.0013-1.1032.4401-2.1611 1.2201-2.9412.7801-.7801 1.838-1.2189 2.9412-1.2201z"
4823
+ fill: tintColor,
4824
+ fillRule: "evenodd",
4825
+ d: "M6.127 10.454c.224-.032.403-.05.53-.05.591 0 1.137.153 1.63.459.398.239.713.529.94.872l.188-.248.005-.007.006-.006c.619-.703 1.347-1.07 2.178-1.07.691 0 1.269.204 1.71.626.454.403.686.91.686 1.51 0 .533-.156.994-.476 1.37-.312.383-.738.574-1.254.574-.345 0-.643-.101-.878-.317a1.1 1.1 0 0 1-.353-.843c0-.405.11-.76.342-1.051.153-.193.354-.352.596-.479a1.416 1.416 0 0 0-.492-.07c-.195 0-.316.016-.38.035-.53.226-.938.694-1.208 1.445l-.001.003c-.02.05-.085.289-.202.74-.115.443-.275 1.077-.481 1.901-.414 1.641-.633 2.547-.662 2.74l-.002.01a3.423 3.423 0 0 0-.067.673c0 .337.097.581.272.756.176.177.413.272.733.272.6 0 1.15-.247 1.657-.768.518-.549.864-1.146 1.044-1.791l.001-.004a1.2 1.2 0 0 1 .088-.224.368.368 0 0 1 .161-.164.564.564 0 0 1 .198-.056 2.19 2.19 0 0 1 .276-.014c.159 0 .305.016.42.064.059.025.12.063.167.122.05.063.073.137.073.213 0 .023-.004.048-.005.057a12.52 12.52 0 0 1-.046.245l-.004.015c-.281 1.026-.86 1.917-1.73 2.67l-.007.007c-.776.611-1.605.925-2.484.925-1.08 0-1.93-.45-2.53-1.33-.453.605-1.015 1.024-1.685 1.248l-.01.003-.011.002a3.23 3.23 0 0 1-.664.053c-.974 0-1.703-.35-2.13-1.078A2.05 2.05 0 0 1 2 19.437c0-.52.158-.975.478-1.349.326-.38.749-.572 1.252-.572.372 0 .69.091.913.31.224.218.318.531.318.898 0 .327-.078.621-.241.874a1.706 1.706 0 0 1-.707.597l-.018.009c.158.063.331.095.52.095.467 0 .902-.285 1.295-.966l.002-.005c.071-.115.185-.417.341-.938.154-.51.341-1.209.563-2.096v-.002c.095-.364.198-.767.31-1.21.11-.444.188-.78.235-1.014l.002-.013c.058-.216.098-.36.119-.425.077-.42.113-.709.113-.877 0-.342-.092-.588-.254-.762-.159-.171-.384-.267-.704-.267-.652 0-1.217.251-1.704.768l-.002.002A4.215 4.215 0 0 0 3.79 14.28a1.084 1.084 0 0 1-.065.207.41.41 0 0 1-.14.176l-.01.007-.012.006a.35.35 0 0 1-.104.03 1.16 1.16 0 0 1-.095.01 5.04 5.04 0 0 1-.275.006H2.67l-.061-.061c-.109-.11-.204-.247-.204-.41v-.015l.003-.015c.07-.472.335-1.05.768-1.723l.001-.002c.771-1.165 1.754-1.857 2.949-2.042h.002Z",
4826
+ clipRule: "evenodd"
4827
+ }), /*#__PURE__*/React.createElement("path", {
4828
+ fill: tintColor,
4829
+ d: "M21.084 10.284c.932-.008 2.301-.013 4.107-.013 1.325 0 2.327.003 3.007.007a75.812 75.812 0 0 1 .99.013c.025 0 .047.002.065.003h.002c.01 0 .04.003.067.01l.01.002.011.004c.201.07.37.183.488.347a.966.966 0 0 1 .169.574c0 .3-.078.568-.248.79-.168.221-.411.377-.708.479h-.002a1.01 1.01 0 0 1-.221.034 8.213 8.213 0 0 1-.35.016c-.29.008-.696.012-1.219.012h-1.39l-.038.223v.001c-.198 1.185-.295 2.156-.295 2.916 0 1.446.251 2.746.75 3.905l.004.007c.059.153.105.284.137.393.03.103.053.205.053.29 0 .359-.16.68-.44.961-.278.296-.63.445-1.041.445-.255 0-.492-.03-.654-.139l-.009-.006-.008-.006c-.126-.101-.236-.274-.338-.477l-.006-.012c-.331-.768-.49-1.722-.49-2.852 0-.595.007-1.002.025-1.212v-.005c.118-1.157.377-2.551.776-4.18v-.002c.024-.096.045-.18.061-.25h-1.948c-.008.038-.02.086-.034.143l-.002.007a35.14 35.14 0 0 0-.146.537c-.05.232-.1.448-.15.648v.001a230.673 230.673 0 0 1-1.312 4.936 41.285 41.285 0 0 1-.411 1.384c-.104.322-.19.557-.256.681-.115.262-.28.473-.5.617-.225.146-.49.212-.783.212-.449 0-.807-.173-1.006-.549l-.006-.011-.005-.012a1.37 1.37 0 0 1-.067-.486v-.326l.346-.745c1.24-2.61 2.136-4.858 2.695-6.747l.002-.008.094-.281h-.463c-.662 0-1.105.025-1.346.07-.198.04-.47.173-.824.43l-.007.005-.007.005c-.366.228-.69.542-.97.947-.044.069-.085.13-.125.18a.651.651 0 0 1-.141.136l-.027.017-.03.01a.8.8 0 0 1-.19.03c-.07.005-.156.008-.258.008-.17 0-.335-.021-.465-.09a.437.437 0 0 1-.216-.546c.014-.042.034-.086.057-.132.047-.093.113-.208.198-.343l.003-.005c1.147-1.745 2.311-2.774 3.508-2.96a2.345 2.345 0 0 1 .158-.015 60.295 60.295 0 0 1 1.369-.026Z"
4813
4830
  })), /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("clipPath", {
4814
- id: "clip0_4011_87172"
4831
+ id: "a"
4815
4832
  }, /*#__PURE__*/React.createElement("path", {
4816
4833
  fill: "#fff",
4817
- transform: "translate(3 10.5186)",
4818
- d: "M0 0h29v10.9635H0z"
4834
+ d: "M0 0h28v11.457H0z",
4835
+ transform: "translate(2 10.271)"
4819
4836
  }))));
4820
4837
  }
4838
+ case "Dismiss":
4839
+ {
4840
+ return /*#__PURE__*/React.createElement("svg", {
4841
+ width: "44",
4842
+ height: "44",
4843
+ viewBox: "0 0 44 44",
4844
+ fill: "none",
4845
+ xmlns: "http://www.w3.org/2000/svg"
4846
+ }, /*#__PURE__*/React.createElement("path", {
4847
+ fillRule: "evenodd",
4848
+ clipRule: "evenodd",
4849
+ d: "M28.7071 15.2929C28.3166 14.9024 27.6834 14.9024 27.2929 15.2929L22 20.5858L16.7071 15.2929C16.3166 14.9024 15.6834 14.9024 15.2929 15.2929C14.9024 15.6834 14.9024 16.3166 15.2929 16.7071L20.5858 22L15.2929 27.2929C14.9024 27.6834 14.9024 28.3166 15.2929 28.7071C15.6834 29.0976 16.3166 29.0976 16.7071 28.7071L22 23.4142L27.2929 28.7071C27.6834 29.0976 28.3166 29.0976 28.7071 28.7071C29.0976 28.3166 29.0976 27.6834 28.7071 27.2929L23.4142 22L28.7071 16.7071C29.0976 16.3166 29.0976 15.6834 28.7071 15.2929Z",
4850
+ fill: tintColor
4851
+ }));
4852
+ }
4821
4853
  default:
4822
4854
  {
4823
4855
  // type as never;
@@ -4891,7 +4923,9 @@ class TabbarItem extends React.Component {
4891
4923
  return /*#__PURE__*/React.createElement(Clickable, {
4892
4924
  onClick: onClick,
4893
4925
  disabled: itemState === "disabled",
4894
- "aria-label": itemType
4926
+ "aria-label": itemType,
4927
+ "aria-selected": itemState === "active",
4928
+ role: "tab"
4895
4929
  }, ({
4896
4930
  hovered,
4897
4931
  focused,
@@ -4918,19 +4952,28 @@ const styles$7 = StyleSheet.create({
4918
4952
  tabbar: {
4919
4953
  display: "flex",
4920
4954
  flexDirection: "row",
4955
+ justifyContent: "space-between",
4921
4956
  paddingTop: 2,
4922
4957
  paddingBottom: 2
4958
+ },
4959
+ pages: {
4960
+ display: "flex",
4961
+ flexDirection: "row"
4923
4962
  }
4924
4963
  });
4925
4964
  function Tabbar(props) {
4926
4965
  const {
4927
4966
  items,
4967
+ onClickClose,
4928
4968
  selectedItem,
4929
4969
  onSelectItem,
4930
4970
  style
4931
4971
  } = props;
4932
4972
  return /*#__PURE__*/React.createElement(View$1, {
4933
- style: [styles$7.tabbar, style]
4973
+ style: [styles$7.tabbar, style],
4974
+ role: "tablist"
4975
+ }, /*#__PURE__*/React.createElement(View$1, {
4976
+ style: [styles$7.pages]
4934
4977
  }, items.map(item => /*#__PURE__*/React.createElement(TabbarItem, {
4935
4978
  key: `tabbar-item-${item}`,
4936
4979
  itemState: item === selectedItem ? "active" : "inactive",
@@ -4938,6 +4981,10 @@ function Tabbar(props) {
4938
4981
  onClick: () => {
4939
4982
  onSelectItem(item);
4940
4983
  }
4984
+ }))), /*#__PURE__*/React.createElement(View$1, null, onClickClose && /*#__PURE__*/React.createElement(TabbarItem, {
4985
+ itemState: "inactive",
4986
+ itemType: "Dismiss",
4987
+ onClick: onClickClose
4941
4988
  })));
4942
4989
  }
4943
4990
 
@@ -7879,12 +7926,15 @@ function ButtonAsset({
7879
7926
  case "PERCENT":
7880
7927
  return /*#__PURE__*/React.createElement("svg", {
7881
7928
  xmlns: "http://www.w3.org/2000/svg",
7882
- width: "20",
7883
- height: "20",
7884
- fill: "currentColor",
7885
- viewBox: "0 0 256 256"
7929
+ width: "40",
7930
+ height: "40",
7931
+ fill: "none",
7932
+ viewBox: "0 0 40 40"
7886
7933
  }, /*#__PURE__*/React.createElement("path", {
7887
- d: "M205.66,61.64l-144,144a8,8,0,0,1-11.32-11.32l144-144a8,8,0,0,1,11.32,11.31ZM50.54,101.44a36,36,0,0,1,50.92-50.91h0a36,36,0,0,1-50.92,50.91ZM56,76A20,20,0,1,0,90.14,61.84h0A20,20,0,0,0,56,76ZM216,180a36,36,0,1,1-10.54-25.46h0A35.76,35.76,0,0,1,216,180Zm-16,0a20,20,0,1,0-5.86,14.14A19.87,19.87,0,0,0,200,180Z"
7934
+ fill: "currentColor",
7935
+ fillRule: "evenodd",
7936
+ d: "M24.447 11.106a1 1 0 0 1 .447 1.341l-8 16a1 1 0 1 1-1.788-.894l8-16a1 1 0 0 1 1.341-.447ZM15 13a2 2 0 1 0 0 4 2 2 0 0 0 0-4Zm-4 2a4 4 0 1 1 8 0 4 4 0 0 1-8 0Zm12 10a2 2 0 1 1 4 0 2 2 0 0 1-4 0Zm2-4a4 4 0 1 0 0 8 4 4 0 0 0 0-8Z",
7937
+ clipRule: "evenodd"
7888
7938
  }));
7889
7939
  case "PI":
7890
7940
  return /*#__PURE__*/React.createElement("svg", {
@@ -7966,6 +8016,28 @@ function ButtonAsset({
7966
8016
  d: "M9 9c-.55228 0-1 .44772-1 1v6c0 .5523.44772 1 1 1h6c.5523 0 1-.4477 1-1v-6c0-.55228-.4477-1-1-1H9zm5 2h-4v4h4v-4z",
7967
8017
  fill: "#21242C"
7968
8018
  }));
8019
+ case "JUMP_OUT_BASE":
8020
+ return /*#__PURE__*/React.createElement("svg", {
8021
+ width: "40",
8022
+ height: "40",
8023
+ viewBox: "0 0 40 40",
8024
+ fill: "none",
8025
+ style: {
8026
+ display: "block",
8027
+ transform: "scale(1,-1)"
8028
+ },
8029
+ xmlns: "http://www.w3.org/2000/svg"
8030
+ }, /*#__PURE__*/React.createElement("path", {
8031
+ fillRule: "evenodd",
8032
+ clipRule: "evenodd",
8033
+ d: "M18.2929 15.2929c.3905-.3905 1.0237-.3905 1.4142 0L26 21.5858V20c0-.5523.4477-1 1-1s1 .4477 1 1v4.003c-.0004.1345-.0273.2627-.0759.3798-.0477.1152-.1178.2234-.2105.3177a.809004.809004 0 01-.0131.0131c-.1797.1765-.4259.2856-.6975.2864H23c-.5523 0-1-.4477-1-1s.4477-1 1-1h1.5858l-6.2929-6.2929c-.3905-.3905-.3905-1.0237 0-1.4142zM31 33c-.5523 0-1-.4477-1-1V16c0-.5523.4477-1 1-1s1 .4477 1 1v16c0 .5523-.4477 1-1 1z",
8034
+ fill: "#1865F2"
8035
+ }), /*#__PURE__*/React.createElement("path", {
8036
+ fillRule: "evenodd",
8037
+ clipRule: "evenodd",
8038
+ d: "M9 9c-.55228 0-1 .44772-1 1v6c0 .5523.44772 1 1 1h6c.5523 0 1-.4477 1-1v-6c0-.55228-.4477-1-1-1H9zm5 2h-4v4h4v-4z",
8039
+ fill: "#21242C"
8040
+ }));
7969
8041
  case "JUMP_INTO_NUMERATOR":
7970
8042
  return /*#__PURE__*/React.createElement("svg", {
7971
8043
  width: "40",
@@ -8079,7 +8151,6 @@ function ButtonAsset({
8079
8151
  case "DOWN":
8080
8152
  case "LEFT":
8081
8153
  case "RIGHT":
8082
- case "JUMP_OUT_BASE":
8083
8154
  case "PHI":
8084
8155
  case "NTHROOT3":
8085
8156
  case "POW":
@@ -8245,7 +8316,7 @@ const styles$1 = StyleSheet.create({
8245
8316
  }
8246
8317
  });
8247
8318
 
8248
- const columns = 4;
8319
+ const columns = 3;
8249
8320
  function ExtrasPage(props) {
8250
8321
  const {
8251
8322
  extraKeys,
@@ -8287,18 +8358,21 @@ function NumbersPage(props) {
8287
8358
  const {
8288
8359
  onClickKey
8289
8360
  } = props;
8361
+ // These keys are arranged sequentially so that tabbing follows numerical order. This
8362
+ // allows us to visually mimic a keypad without affecting a11y. The visual order of the
8363
+ // keys in the keypad is determined by their coordinates, not their order in the DOM.
8290
8364
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(KeypadButton, {
8291
- keyConfig: KeyConfigs.NUM_7,
8365
+ keyConfig: KeyConfigs.NUM_1,
8292
8366
  onClickKey: onClickKey,
8293
- coord: [0, 0]
8367
+ coord: [0, 2]
8294
8368
  }), /*#__PURE__*/React.createElement(KeypadButton, {
8295
- keyConfig: KeyConfigs.NUM_8,
8369
+ keyConfig: KeyConfigs.NUM_2,
8296
8370
  onClickKey: onClickKey,
8297
- coord: [1, 0]
8371
+ coord: [1, 2]
8298
8372
  }), /*#__PURE__*/React.createElement(KeypadButton, {
8299
- keyConfig: KeyConfigs.NUM_9,
8373
+ keyConfig: KeyConfigs.NUM_3,
8300
8374
  onClickKey: onClickKey,
8301
- coord: [2, 0]
8375
+ coord: [2, 2]
8302
8376
  }), /*#__PURE__*/React.createElement(KeypadButton, {
8303
8377
  keyConfig: KeyConfigs.NUM_4,
8304
8378
  onClickKey: onClickKey,
@@ -8312,17 +8386,17 @@ function NumbersPage(props) {
8312
8386
  onClickKey: onClickKey,
8313
8387
  coord: [2, 1]
8314
8388
  }), /*#__PURE__*/React.createElement(KeypadButton, {
8315
- keyConfig: KeyConfigs.NUM_1,
8389
+ keyConfig: KeyConfigs.NUM_7,
8316
8390
  onClickKey: onClickKey,
8317
- coord: [0, 2]
8391
+ coord: [0, 0]
8318
8392
  }), /*#__PURE__*/React.createElement(KeypadButton, {
8319
- keyConfig: KeyConfigs.NUM_2,
8393
+ keyConfig: KeyConfigs.NUM_8,
8320
8394
  onClickKey: onClickKey,
8321
- coord: [1, 2]
8395
+ coord: [1, 0]
8322
8396
  }), /*#__PURE__*/React.createElement(KeypadButton, {
8323
- keyConfig: KeyConfigs.NUM_3,
8397
+ keyConfig: KeyConfigs.NUM_9,
8324
8398
  onClickKey: onClickKey,
8325
- coord: [2, 2]
8399
+ coord: [2, 0]
8326
8400
  }), /*#__PURE__*/React.createElement(KeypadButton, {
8327
8401
  keyConfig: KeyConfigs.NUM_0,
8328
8402
  onClickKey: onClickKey,
@@ -8335,6 +8409,11 @@ function NumbersPage(props) {
8335
8409
  keyConfig: KeyConfigs.NEGATIVE,
8336
8410
  onClickKey: onClickKey,
8337
8411
  coord: [2, 3]
8412
+ }), /*#__PURE__*/React.createElement(KeypadButton, {
8413
+ keyConfig: KeyConfigs.PERCENT,
8414
+ onClickKey: onClickKey,
8415
+ coord: [3, 0],
8416
+ secondary: true
8338
8417
  }));
8339
8418
  }
8340
8419
 
@@ -8401,12 +8480,39 @@ function OperatorsPage(props) {
8401
8480
  })));
8402
8481
  }
8403
8482
 
8483
+ function getCursorContextConfig(cursorContext) {
8484
+ if (!cursorContext) {
8485
+ return null;
8486
+ }
8487
+ switch (cursorContext) {
8488
+ case CursorContext.NONE:
8489
+ return null;
8490
+ case CursorContext.IN_PARENS:
8491
+ return KeyConfigs.JUMP_OUT_PARENTHESES;
8492
+ case CursorContext.IN_SUPER_SCRIPT:
8493
+ return KeyConfigs.JUMP_OUT_EXPONENT;
8494
+ case CursorContext.IN_SUB_SCRIPT:
8495
+ return KeyConfigs.JUMP_OUT_BASE;
8496
+ case CursorContext.IN_NUMERATOR:
8497
+ return KeyConfigs.JUMP_OUT_NUMERATOR;
8498
+ case CursorContext.IN_DENOMINATOR:
8499
+ return KeyConfigs.JUMP_OUT_DENOMINATOR;
8500
+ case CursorContext.BEFORE_FRACTION:
8501
+ return KeyConfigs.JUMP_INTO_NUMERATOR;
8502
+ }
8503
+ }
8404
8504
  function SharedKeys(props) {
8405
8505
  const {
8406
8506
  onClickKey,
8507
+ cursorContext,
8407
8508
  divisionKey,
8408
- multiplicationDot
8509
+ multiplicationDot,
8510
+ selectedPage
8409
8511
  } = props;
8512
+ const cursorKeyConfig = getCursorContextConfig(cursorContext);
8513
+
8514
+ // Fraction position depends on the page
8515
+ const fractionCoord = selectedPage === "Numbers" || selectedPage === "Operators" ? [3, 1] : [3, 0];
8410
8516
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(KeypadButton, {
8411
8517
  keyConfig: KeyConfigs.PLUS,
8412
8518
  onClickKey: onClickKey,
@@ -8417,6 +8523,11 @@ function SharedKeys(props) {
8417
8523
  onClickKey: onClickKey,
8418
8524
  coord: [5, 0],
8419
8525
  secondary: true
8526
+ }), /*#__PURE__*/React.createElement(KeypadButton, {
8527
+ keyConfig: KeyConfigs.FRAC_INCLUSIVE,
8528
+ onClickKey: onClickKey,
8529
+ coord: fractionCoord,
8530
+ secondary: true
8420
8531
  }), /*#__PURE__*/React.createElement(KeypadButton, {
8421
8532
  keyConfig: multiplicationDot ? KeyConfigs.CDOT : KeyConfigs.TIMES,
8422
8533
  onClickKey: onClickKey,
@@ -8437,8 +8548,8 @@ function SharedKeys(props) {
8437
8548
  onClickKey: onClickKey,
8438
8549
  coord: [5, 2],
8439
8550
  secondary: true
8440
- }), /*#__PURE__*/React.createElement(KeypadButton, {
8441
- keyConfig: KeyConfigs.FRAC_INCLUSIVE,
8551
+ }), cursorKeyConfig && /*#__PURE__*/React.createElement(KeypadButton, {
8552
+ keyConfig: cursorKeyConfig,
8442
8553
  onClickKey: onClickKey,
8443
8554
  coord: [4, 3],
8444
8555
  secondary: true
@@ -8450,6 +8561,9 @@ function SharedKeys(props) {
8450
8561
  }));
8451
8562
  }
8452
8563
 
8564
+ const defaultProps = {
8565
+ extraKeys: []
8566
+ };
8453
8567
  function allPages(props) {
8454
8568
  var _props$extraKeys;
8455
8569
  const pages = ["Numbers"];
@@ -8466,12 +8580,16 @@ function allPages(props) {
8466
8580
  }
8467
8581
  return pages;
8468
8582
  }
8583
+
8584
+ // The main (v2) Keypad. Use this component to present an accessible, onscreen
8585
+ // keypad to learners for entering math expressions.
8469
8586
  function Keypad(props) {
8470
8587
  const [selectedPage, setSelectedPage] = React.useState("Numbers");
8471
8588
  const availablePages = allPages(props);
8472
8589
  const {
8473
8590
  onClickKey,
8474
- extraKeys = [],
8591
+ cursorContext,
8592
+ extraKeys,
8475
8593
  multiplicationDot,
8476
8594
  divisionKey,
8477
8595
  preAlgebra,
@@ -8485,9 +8603,13 @@ function Keypad(props) {
8485
8603
  onSelectItem: tabbarItem => {
8486
8604
  setSelectedPage(tabbarItem);
8487
8605
  },
8488
- style: styles.tabbar
8606
+ style: styles.tabbar,
8607
+ onClickClose: () => onClickKey("DISMISS")
8489
8608
  }), /*#__PURE__*/React.createElement(View$1, {
8490
- style: styles.grid
8609
+ style: styles.grid,
8610
+ role: "grid",
8611
+ tabIndex: 0,
8612
+ "aria-label": "Keypad"
8491
8613
  }, selectedPage === "Numbers" && /*#__PURE__*/React.createElement(NumbersPage, {
8492
8614
  onClickKey: onClickKey
8493
8615
  }), selectedPage === "Extras" && /*#__PURE__*/React.createElement(ExtrasPage, {
@@ -8503,10 +8625,13 @@ function Keypad(props) {
8503
8625
  onClickKey: onClickKey
8504
8626
  }), /*#__PURE__*/React.createElement(SharedKeys, {
8505
8627
  onClickKey: onClickKey,
8628
+ cursorContext: cursorContext,
8506
8629
  multiplicationDot: multiplicationDot,
8507
- divisionKey: divisionKey
8630
+ divisionKey: divisionKey,
8631
+ selectedPage: selectedPage
8508
8632
  })));
8509
8633
  }
8634
+ Keypad.defaultProps = defaultProps;
8510
8635
  const styles = StyleSheet.create({
8511
8636
  tabbar: {
8512
8637
  background: Color.white