@khanacademy/math-input 8.1.3 → 9.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 (174) hide show
  1. package/CHANGELOG.md +14 -1
  2. package/dist/components/input/cursor-contexts.d.ts +9 -9
  3. package/dist/components/input/math-wrapper.d.ts +4 -4
  4. package/dist/components/input/mathquill-helpers.d.ts +1 -1
  5. package/dist/components/input/mathquill-instance.d.ts +1 -1
  6. package/dist/components/input/mathquill-types.d.ts +1 -1
  7. package/dist/components/key-handlers/handle-arrow.d.ts +2 -2
  8. package/dist/components/key-handlers/handle-backspace.d.ts +1 -1
  9. package/dist/components/key-handlers/handle-exponent.d.ts +2 -2
  10. package/dist/components/key-handlers/handle-jump-out.d.ts +2 -2
  11. package/dist/components/key-handlers/key-translator.d.ts +2 -2
  12. package/dist/components/keypad/button-assets.d.ts +1 -1
  13. package/dist/components/keypad/keypad-button.d.ts +1 -1
  14. package/dist/components/keypad/keypad-pages/extras-page.d.ts +2 -2
  15. package/dist/components/keypad/keypad-pages/fractions-page.d.ts +9 -0
  16. package/dist/components/keypad/keypad-pages/geometry-page.d.ts +1 -1
  17. package/dist/components/keypad/keypad-pages/numbers-page.d.ts +1 -1
  18. package/dist/components/keypad/keypad-pages/operators-page.d.ts +1 -1
  19. package/dist/components/keypad/keypad.d.ts +4 -3
  20. package/dist/components/keypad/mobile-keypad.d.ts +1 -1
  21. package/dist/components/keypad/shared-keys.d.ts +3 -3
  22. package/dist/components/keypad/utils.d.ts +2 -0
  23. package/dist/components/keypad-legacy/compute-layout-parameters.d.ts +1 -1
  24. package/dist/components/keypad-legacy/empty-keypad-button.d.ts +1 -1
  25. package/dist/components/keypad-legacy/gesture-manager.d.ts +3 -3
  26. package/dist/components/keypad-legacy/gesture-state-machine.d.ts +1 -1
  27. package/dist/components/keypad-legacy/keypad-button.d.ts +2 -1
  28. package/dist/components/keypad-legacy/multi-symbol-grid.d.ts +1 -1
  29. package/dist/components/keypad-legacy/multi-symbol-popover.d.ts +1 -1
  30. package/dist/components/keypad-legacy/node-manager.d.ts +1 -1
  31. package/dist/components/keypad-legacy/store/actions.d.ts +1 -1
  32. package/dist/components/keypad-legacy/store/types.d.ts +3 -3
  33. package/dist/components/keypad-legacy/touchable-keypad-button.d.ts +3 -3
  34. package/dist/components/keypad-switch.d.ts +1 -1
  35. package/dist/components/tabbar/tabbar.d.ts +2 -2
  36. package/dist/components/tabbar/types.d.ts +1 -1
  37. package/dist/data/key-configs.d.ts +2 -2
  38. package/dist/es/index.js +847 -240
  39. package/dist/es/index.js.map +1 -1
  40. package/dist/index.js +847 -240
  41. package/dist/index.js.map +1 -1
  42. package/dist/types.d.ts +6 -5
  43. package/package.json +6 -6
  44. package/src/components/input/cursor-contexts.ts +9 -9
  45. package/src/components/input/math-input.tsx +12 -12
  46. package/src/components/input/math-wrapper.ts +7 -3
  47. package/src/components/input/mathquill-helpers.ts +3 -5
  48. package/src/components/input/mathquill-instance.ts +1 -1
  49. package/src/components/input/mathquill-types.ts +1 -1
  50. package/src/components/key-handlers/handle-arrow.ts +4 -3
  51. package/src/components/key-handlers/handle-backspace.ts +3 -2
  52. package/src/components/key-handlers/handle-exponent.ts +4 -5
  53. package/src/components/key-handlers/handle-jump-out.ts +4 -5
  54. package/src/components/key-handlers/key-translator.ts +6 -5
  55. package/src/components/keypad/__tests__/keypad-button.test.tsx +44 -3
  56. package/src/components/keypad/__tests__/keypad-v2-mathquill.test.tsx +4 -3
  57. package/src/components/keypad/__tests__/keypad-v2.cypress.ts +2 -32
  58. package/src/components/keypad/__tests__/keypad.test.tsx +46 -0
  59. package/src/components/keypad/__tests__/test-data-tabs.ts +21 -0
  60. package/src/components/keypad/button-assets.tsx +761 -60
  61. package/src/components/keypad/keypad-button.stories.tsx +4 -2
  62. package/src/components/keypad/keypad-button.tsx +2 -3
  63. package/src/components/keypad/keypad-mathquill.stories.tsx +3 -2
  64. package/src/components/keypad/keypad-pages/extras-page.tsx +3 -2
  65. package/src/components/keypad/keypad-pages/fractions-page.tsx +125 -0
  66. package/src/components/keypad/keypad-pages/geometry-page.tsx +2 -1
  67. package/src/components/keypad/keypad-pages/numbers-page.tsx +2 -1
  68. package/src/components/keypad/keypad-pages/operators-page.tsx +2 -1
  69. package/src/components/keypad/keypad.stories.tsx +17 -2
  70. package/src/components/keypad/keypad.tsx +56 -22
  71. package/src/components/keypad/mobile-keypad.tsx +2 -1
  72. package/src/components/keypad/shared-keys.tsx +5 -28
  73. package/src/components/keypad/utils.ts +30 -0
  74. package/src/components/keypad-context.ts +1 -1
  75. package/src/components/keypad-legacy/compute-layout-parameters.ts +1 -1
  76. package/src/components/keypad-legacy/echo-manager.tsx +1 -1
  77. package/src/components/keypad-legacy/empty-keypad-button.tsx +1 -1
  78. package/src/components/keypad-legacy/gesture-manager.ts +4 -4
  79. package/src/components/keypad-legacy/gesture-state-machine.ts +1 -1
  80. package/src/components/keypad-legacy/keypad-button.tsx +2 -1
  81. package/src/components/keypad-legacy/many-keypad-button.tsx +2 -1
  82. package/src/components/keypad-legacy/multi-symbol-grid.tsx +2 -1
  83. package/src/components/keypad-legacy/multi-symbol-popover.tsx +2 -1
  84. package/src/components/keypad-legacy/node-manager.ts +1 -1
  85. package/src/components/keypad-legacy/store/actions.ts +1 -2
  86. package/src/components/keypad-legacy/store/index.ts +1 -1
  87. package/src/components/keypad-legacy/store/types.ts +3 -4
  88. package/src/components/keypad-legacy/touchable-keypad-button.tsx +3 -3
  89. package/src/components/keypad-legacy/two-page-keypad.tsx +1 -1
  90. package/src/components/keypad-switch.tsx +2 -1
  91. package/src/components/tabbar/tabbar.tsx +4 -2
  92. package/src/components/tabbar/types.ts +1 -0
  93. package/src/data/key-configs.ts +4 -3
  94. package/src/full-math-input.stories.tsx +35 -3
  95. package/src/types.ts +6 -6
  96. package/tsconfig-build.tsbuildinfo +1 -1
  97. package/dist/components/common-style.js.flow +0 -27
  98. package/dist/components/input/cursor-contexts.js.flow +0 -26
  99. package/dist/components/input/cursor-handle.js.flow +0 -28
  100. package/dist/components/input/drag-listener.js.flow +0 -19
  101. package/dist/components/input/math-input.js.flow +0 -153
  102. package/dist/components/input/math-wrapper.js.flow +0 -54
  103. package/dist/components/input/mathquill-helpers.js.flow +0 -56
  104. package/dist/components/input/mathquill-instance.js.flow +0 -24
  105. package/dist/components/input/mathquill-types.js.flow +0 -365
  106. package/dist/components/input/scroll-into-view.js.flow +0 -20
  107. package/dist/components/key-handlers/handle-arrow.js.flow +0 -12
  108. package/dist/components/key-handlers/handle-backspace.js.flow +0 -14
  109. package/dist/components/key-handlers/handle-exponent.js.flow +0 -12
  110. package/dist/components/key-handlers/handle-jump-out.js.flow +0 -14
  111. package/dist/components/key-handlers/key-translator.js.flow +0 -10
  112. package/dist/components/keypad/button-assets.js.flow +0 -12
  113. package/dist/components/keypad/index.js.flow +0 -8
  114. package/dist/components/keypad/keypad-button.js.flow +0 -18
  115. package/dist/components/keypad/keypad-pages/extras-page.js.flow +0 -13
  116. package/dist/components/keypad/keypad-pages/geometry-page.js.flow +0 -11
  117. package/dist/components/keypad/keypad-pages/numbers-page.js.flow +0 -11
  118. package/dist/components/keypad/keypad-pages/operators-page.js.flow +0 -15
  119. package/dist/components/keypad/keypad.js.flow +0 -37
  120. package/dist/components/keypad/mobile-keypad.js.flow +0 -57
  121. package/dist/components/keypad/shared-keys.js.flow +0 -20
  122. package/dist/components/keypad-context.js.flow +0 -18
  123. package/dist/components/keypad-legacy/compute-layout-parameters.js.flow +0 -21
  124. package/dist/components/keypad-legacy/corner-decal.js.flow +0 -15
  125. package/dist/components/keypad-legacy/echo-manager.js.flow +0 -20
  126. package/dist/components/keypad-legacy/empty-keypad-button.js.flow +0 -23
  127. package/dist/components/keypad-legacy/expression-keypad.js.flow +0 -34
  128. package/dist/components/keypad-legacy/fraction-keypad.js.flow +0 -33
  129. package/dist/components/keypad-legacy/gesture-manager.js.flow +0 -97
  130. package/dist/components/keypad-legacy/gesture-state-machine.js.flow +0 -118
  131. package/dist/components/keypad-legacy/icon.js.flow +0 -18
  132. package/dist/components/keypad-legacy/index.js.flow +0 -7
  133. package/dist/components/keypad-legacy/keypad-button.js.flow +0 -80
  134. package/dist/components/keypad-legacy/keypad-container.js.flow +0 -63
  135. package/dist/components/keypad-legacy/keypad.js.flow +0 -40
  136. package/dist/components/keypad-legacy/many-keypad-button.js.flow +0 -17
  137. package/dist/components/keypad-legacy/math-icon.js.flow +0 -19
  138. package/dist/components/keypad-legacy/multi-symbol-grid.js.flow +0 -16
  139. package/dist/components/keypad-legacy/multi-symbol-popover.js.flow +0 -15
  140. package/dist/components/keypad-legacy/navigation-pad.js.flow +0 -16
  141. package/dist/components/keypad-legacy/node-manager.js.flow +0 -60
  142. package/dist/components/keypad-legacy/popover-manager.js.flow +0 -15
  143. package/dist/components/keypad-legacy/popover-state-machine.js.flow +0 -77
  144. package/dist/components/keypad-legacy/provided-keypad.js.flow +0 -38
  145. package/dist/components/keypad-legacy/store/actions.js.flow +0 -90
  146. package/dist/components/keypad-legacy/store/echo-reducer.js.flow +0 -10
  147. package/dist/components/keypad-legacy/store/index.js.flow +0 -22
  148. package/dist/components/keypad-legacy/store/input-reducer.js.flow +0 -13
  149. package/dist/components/keypad-legacy/store/keypad-reducer.js.flow +0 -13
  150. package/dist/components/keypad-legacy/store/layout-reducer.js.flow +0 -13
  151. package/dist/components/keypad-legacy/store/shared.js.flow +0 -14
  152. package/dist/components/keypad-legacy/store/types.js.flow +0 -53
  153. package/dist/components/keypad-legacy/styles.js.flow +0 -11
  154. package/dist/components/keypad-legacy/svg-icon.js.flow +0 -15
  155. package/dist/components/keypad-legacy/text-icon.js.flow +0 -16
  156. package/dist/components/keypad-legacy/touchable-keypad-button.js.flow +0 -59
  157. package/dist/components/keypad-legacy/two-page-keypad.js.flow +0 -31
  158. package/dist/components/keypad-legacy/z-indexes.js.flow +0 -13
  159. package/dist/components/keypad-switch.js.flow +0 -15
  160. package/dist/components/prop-types.js.flow +0 -17
  161. package/dist/components/tabbar/icons.js.flow +0 -14
  162. package/dist/components/tabbar/index.js.flow +0 -8
  163. package/dist/components/tabbar/item.js.flow +0 -19
  164. package/dist/components/tabbar/tabbar.js.flow +0 -18
  165. package/dist/components/tabbar/types.js.flow +0 -12
  166. package/dist/data/key-configs.js.flow +0 -10
  167. package/dist/data/keys.js.flow +0 -122
  168. package/dist/enums.js.flow +0 -54
  169. package/dist/fake-react-native-web/index.js.flow +0 -8
  170. package/dist/fake-react-native-web/text.js.flow +0 -19
  171. package/dist/fake-react-native-web/view.js.flow +0 -29
  172. package/dist/index.js.flow +0 -25
  173. package/dist/types.js.flow +0 -91
  174. package/dist/utils.js.flow +0 -7
package/dist/types.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- import ReactDOM from "react-dom";
2
- import { CursorContext } from "./components/input/cursor-contexts";
3
- import Key from "./data/keys";
4
- import { BorderDirection, EchoAnimationType, IconType, KeyType, KeypadType } from "./enums";
1
+ import type { CursorContext } from "./components/input/cursor-contexts";
2
+ import type Key from "./data/keys";
3
+ import type { BorderDirection, EchoAnimationType, IconType, KeyType, KeypadType } from "./enums";
4
+ import type * as React from "react";
5
+ import type ReactDOM from "react-dom";
5
6
  export type Border = Partial<ReadonlyArray<BorderDirection>>;
6
7
  export interface Bound {
7
8
  top: number;
@@ -62,7 +63,7 @@ export type ActiveNodesObj = {
62
63
  export type LayoutProps = {
63
64
  initialBounds: Bound;
64
65
  };
65
- export type ClickKeyCallback = (key: Key) => void;
66
+ export type ClickKeyCallback = (key: Key, event?: React.SyntheticEvent) => void;
66
67
  export interface KeypadAPI {
67
68
  activate: () => void;
68
69
  dismiss: () => void;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Khan Academy's new expression editor for the mobile web.",
4
4
  "author": "Khan Academy",
5
5
  "license": "MIT",
6
- "version": "8.1.3",
6
+ "version": "9.0.0",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },
@@ -24,16 +24,16 @@
24
24
  "performance-now": "^0.2.0"
25
25
  },
26
26
  "devDependencies": {
27
- "@khanacademy/wonder-blocks-clickable": "^3.0.8",
27
+ "@khanacademy/wonder-blocks-clickable": "^4.0.0",
28
28
  "@khanacademy/wonder-blocks-color": "^2.0.1",
29
- "@khanacademy/wonder-blocks-core": "^5.0.4",
29
+ "@khanacademy/wonder-blocks-core": "^6.0.0",
30
30
  "@khanacademy/wonder-blocks-i18n": "^2.0.2",
31
31
  "@khanacademy/wonder-blocks-popover": "^2.0.11",
32
32
  "@khanacademy/wonder-stuff-core": "^1.2.2",
33
33
  "aphrodite": "^1.1.0",
34
34
  "jquery": "^2.1.1",
35
35
  "katex": "^0.11.1",
36
- "perseus-build-settings": "^0.1.0",
36
+ "perseus-build-settings": "^0.2.0",
37
37
  "prop-types": "15.6.1",
38
38
  "react": "^16.8.0",
39
39
  "react-dom": "^16.8.0",
@@ -44,9 +44,9 @@
44
44
  "redux": "^4.0.0"
45
45
  },
46
46
  "peerDependencies": {
47
- "@khanacademy/wonder-blocks-clickable": "^3.0.8",
47
+ "@khanacademy/wonder-blocks-clickable": "^4.0.0",
48
48
  "@khanacademy/wonder-blocks-color": "^2.0.1",
49
- "@khanacademy/wonder-blocks-core": "^5.0.4",
49
+ "@khanacademy/wonder-blocks-core": "^6.0.0",
50
50
  "@khanacademy/wonder-blocks-i18n": "^2.0.2",
51
51
  "@khanacademy/wonder-stuff-core": "^1.2.2",
52
52
  "aphrodite": "^1.1.0",
@@ -10,28 +10,28 @@
10
10
  * the radical.
11
11
  */
12
12
 
13
- export const CursorContext = {
13
+ export enum CursorContext {
14
14
  // The cursor is not in any of the other viable contexts.
15
- NONE: "NONE",
15
+ NONE = "NONE",
16
16
 
17
17
  // The cursor is within a set of parentheses.
18
- IN_PARENS: "IN_PARENS",
18
+ IN_PARENS = "IN_PARENS",
19
19
 
20
20
  // The cursor is within a superscript (e.g., an exponent).
21
- IN_SUPER_SCRIPT: "IN_SUPER_SCRIPT",
21
+ IN_SUPER_SCRIPT = "IN_SUPER_SCRIPT",
22
22
 
23
23
  // The cursor is within a subscript (e.g., the base of a custom logarithm).
24
- IN_SUB_SCRIPT: "IN_SUB_SCRIPT",
24
+ IN_SUB_SCRIPT = "IN_SUB_SCRIPT",
25
25
 
26
26
  // The cursor is in the numerator of a fraction.
27
- IN_NUMERATOR: "IN_NUMERATOR",
27
+ IN_NUMERATOR = "IN_NUMERATOR",
28
28
 
29
29
  // The cursor is in the denominator of a fraction.
30
- IN_DENOMINATOR: "IN_DENOMINATOR",
30
+ IN_DENOMINATOR = "IN_DENOMINATOR",
31
31
 
32
32
  // The cursor is sitting before a fraction; that is, the cursor is within
33
33
  // what looks to be a mixed number preceding a fraction. This will only be
34
34
  // the case when the only math between the cursor and the fraction to its
35
35
  // write is non-leaf math (numbers and variables).
36
- BEFORE_FRACTION: "BEFORE_FRACTION",
37
- } as const;
36
+ BEFORE_FRACTION = "BEFORE_FRACTION",
37
+ }
@@ -54,18 +54,18 @@ class MathInput extends React.Component<Props, State> {
54
54
  didTouchOutside: boolean | null | undefined;
55
55
  didScroll: boolean | null | undefined;
56
56
  mathField: any;
57
- // @ts-expect-error [FEI-5003] - TS2564 - Property 'recordTouchStartOutside' has no initializer and is not definitely assigned in the constructor.
57
+ // @ts-expect-error - TS2564 - Property 'recordTouchStartOutside' has no initializer and is not definitely assigned in the constructor.
58
58
  recordTouchStartOutside: (arg1: any) => void;
59
- // @ts-expect-error [FEI-5003] - TS2564 - Property 'blurOnTouchEndOutside' has no initializer and is not definitely assigned in the constructor.
59
+ // @ts-expect-error - TS2564 - Property 'blurOnTouchEndOutside' has no initializer and is not definitely assigned in the constructor.
60
60
  blurOnTouchEndOutside: (arg1: any) => void;
61
61
  dragListener: any;
62
62
  inputRef: HTMLDivElement | null | undefined;
63
63
  _isMounted: boolean | null | undefined;
64
64
  _mathContainer: any;
65
- // @ts-expect-error [FEI-5003] - TS2564 - Property '_container' has no initializer and is not definitely assigned in the constructor.
65
+ // @ts-expect-error - TS2564 - Property '_container' has no initializer and is not definitely assigned in the constructor.
66
66
  _container: HTMLDivElement;
67
67
  _root: any;
68
- // @ts-expect-error [FEI-5003] - TS2564 - Property '_containerBounds' has no initializer and is not definitely assigned in the constructor.
68
+ // @ts-expect-error - TS2564 - Property '_containerBounds' has no initializer and is not definitely assigned in the constructor.
69
69
  _containerBounds: ClientRect;
70
70
  _keypadBounds: ClientRect | null | undefined;
71
71
 
@@ -235,11 +235,11 @@ class MathInput extends React.Component<Props, State> {
235
235
  window.removeEventListener("touchstart", this.recordTouchStartOutside);
236
236
  window.removeEventListener("touchend", this.blurOnTouchEndOutside);
237
237
  window.removeEventListener("touchcancel", this.blurOnTouchEndOutside);
238
- // @ts-expect-error [FEI-5003] - TS2769 - No overload matches this call.
238
+ // @ts-expect-error - TS2769 - No overload matches this call.
239
239
  window.removeEventListener("resize", this._clearKeypadBoundsCache());
240
240
  window.removeEventListener(
241
241
  "orientationchange",
242
- // @ts-expect-error [FEI-5003] - TS2769 - No overload matches this call.
242
+ // @ts-expect-error - TS2769 - No overload matches this call.
243
243
  this._clearKeypadBoundsCache(),
244
244
  );
245
245
  }
@@ -430,7 +430,7 @@ class MathInput extends React.Component<Props, State> {
430
430
  ];
431
431
 
432
432
  const elements = points
433
- // @ts-expect-error [FEI-5003] - TS2556 - A spread argument must either have a tuple type or be passed to a rest parameter.
433
+ // @ts-expect-error - TS2556 - A spread argument must either have a tuple type or be passed to a rest parameter.
434
434
  .map((point) => document.elementFromPoint(...point))
435
435
  // We exclude the root container itself and any nodes marked
436
436
  // as non-leaf which are fractions, parens, and roots. The
@@ -468,16 +468,16 @@ class MathInput extends React.Component<Props, State> {
468
468
  const elementsById: Record<string, any> = {};
469
469
 
470
470
  for (const element of elements) {
471
- // @ts-expect-error [FEI-5003] - TS2531 - Object is possibly 'null'.
471
+ // @ts-expect-error - TS2531 - Object is possibly 'null'.
472
472
  const id = element.getAttribute("mathquill-command-id");
473
473
  if (id != null) {
474
- // @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'Element | null' is not assignable to parameter of type 'HTMLElement | null'.
474
+ // @ts-expect-error - TS2345 - Argument of type 'Element | null' is not assignable to parameter of type 'HTMLElement | null'.
475
475
  leafElements.push(element);
476
476
 
477
477
  counts[id] = (counts[id] || 0) + 1;
478
478
  elementsById[id] = element;
479
479
  } else {
480
- // @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'Element | null' is not assignable to parameter of type 'HTMLElement | null'.
480
+ // @ts-expect-error - TS2345 - Argument of type 'Element | null' is not assignable to parameter of type 'HTMLElement | null'.
481
481
  nonLeafElements.push(element);
482
482
  }
483
483
  }
@@ -506,7 +506,7 @@ class MathInput extends React.Component<Props, State> {
506
506
  // hit count in the situation should not have serious effects on
507
507
  // the overall accuracy of the algorithm.
508
508
  if (hitNode == null && nonLeafElements.length > 0) {
509
- // @ts-expect-error [FEI-5003] - TS2322 - Type 'HTMLElement | null' is not assignable to type 'null'.
509
+ // @ts-expect-error - TS2322 - Type 'HTMLElement | null' is not assignable to type 'null'.
510
510
  hitNode = nonLeafElements[0];
511
511
  }
512
512
 
@@ -908,7 +908,7 @@ class MathInput extends React.Component<Props, State> {
908
908
  overrides.css. */}
909
909
  <div
910
910
  className="keypad-input"
911
- // @ts-expect-error [FEI-5003] - TS2322 - Type 'string' is not assignable to type 'number | undefined'.
911
+ // @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'number | undefined'.
912
912
  tabIndex={"0"}
913
913
  ref={(node) => {
914
914
  this.inputRef = node;
@@ -16,8 +16,6 @@
16
16
 
17
17
  import $ from "jquery";
18
18
 
19
- import Key from "../../data/keys";
20
- import {Cursor} from "../../types";
21
19
  import handleBackspace from "../key-handlers/handle-backspace";
22
20
  import keyTranslator from "../key-handlers/key-translator";
23
21
 
@@ -27,7 +25,13 @@ import {
27
25
  maybeFindCommand,
28
26
  } from "./mathquill-helpers";
29
27
  import {createMathField, mathQuillInstance} from "./mathquill-instance";
30
- import {MathFieldInterface, MathFieldUpdaterCallback} from "./mathquill-types";
28
+
29
+ import type Key from "../../data/keys";
30
+ import type {Cursor} from "../../types";
31
+ import type {
32
+ MathFieldInterface,
33
+ MathFieldUpdaterCallback,
34
+ } from "./mathquill-types";
31
35
 
32
36
  const mobileKeyTranslator: Record<Key, MathFieldUpdaterCallback> = {
33
37
  ...keyTranslator,
@@ -1,10 +1,8 @@
1
1
  import {CursorContext} from "./cursor-contexts";
2
2
  import {mathQuillInstance} from "./mathquill-instance";
3
- import {
4
- MathFieldActionType,
5
- MathFieldCursor,
6
- MathFieldInterface,
7
- } from "./mathquill-types";
3
+ import {MathFieldActionType} from "./mathquill-types";
4
+
5
+ import type {MathFieldCursor, MathFieldInterface} from "./mathquill-types";
8
6
 
9
7
  const Numerals = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
10
8
  const GreekLetters = ["\\theta", "\\pi"];
@@ -1,6 +1,6 @@
1
1
  import MathQuill from "mathquill";
2
2
 
3
- import {MathQuillInterface, MathFieldConfig} from "./mathquill-types";
3
+ import type {MathQuillInterface, MathFieldConfig} from "./mathquill-types";
4
4
 
5
5
  // We only need one MathQuill instance (referred to as MQ in the docs)
6
6
  // and that contains some MQ constants and the MathField constructor
@@ -1,4 +1,4 @@
1
- import Key from "../../data/keys";
1
+ import type Key from "../../data/keys";
2
2
 
3
3
  export interface MathQuillInterface {
4
4
  L: "L";
@@ -1,13 +1,14 @@
1
- import Key from "../../data/keys";
2
1
  import {
3
2
  maybeFindCommand,
4
3
  maybeFindCommandBeforeParens,
5
4
  getCursor,
6
5
  } from "../input/mathquill-helpers";
7
6
  import {mathQuillInstance} from "../input/mathquill-instance";
8
- import {
7
+ import {MathFieldActionType} from "../input/mathquill-types";
8
+
9
+ import type Key from "../../data/keys";
10
+ import type {
9
11
  MathFieldInterface,
10
- MathFieldActionType,
11
12
  MathFieldCursor,
12
13
  } from "../input/mathquill-types";
13
14
 
@@ -10,8 +10,9 @@ import {
10
10
  maybeFindCommandBeforeParens,
11
11
  } from "../input/mathquill-helpers";
12
12
  import {mathQuillInstance} from "../input/mathquill-instance";
13
- import {
14
- MathFieldActionType,
13
+ import {MathFieldActionType} from "../input/mathquill-types";
14
+
15
+ import type {
15
16
  MathFieldInterface,
16
17
  MathFieldCursor,
17
18
  } from "../input/mathquill-types";
@@ -1,10 +1,9 @@
1
- import Key from "../../data/keys";
2
1
  import {getCursor} from "../input/mathquill-helpers";
3
2
  import {mathQuillInstance} from "../input/mathquill-instance";
4
- import {
5
- MathFieldInterface,
6
- MathFieldActionType,
7
- } from "../input/mathquill-types";
3
+ import {MathFieldActionType} from "../input/mathquill-types";
4
+
5
+ import type Key from "../../data/keys";
6
+ import type {MathFieldInterface} from "../input/mathquill-types";
8
7
 
9
8
  const ArithmeticOperators = ["+", "-", "\\cdot", "\\times", "\\div"];
10
9
  const EqualityOperators = ["=", "\\neq", "<", "\\leq", ">", "\\geq"];
@@ -1,4 +1,3 @@
1
- import Key from "../../data/keys";
2
1
  import {CursorContext} from "../input/cursor-contexts";
3
2
  import {
4
3
  isFraction,
@@ -7,10 +6,10 @@ import {
7
6
  getCursor,
8
7
  } from "../input/mathquill-helpers";
9
8
  import {mathQuillInstance} from "../input/mathquill-instance";
10
- import {
11
- MathFieldInterface,
12
- MathFieldActionType,
13
- } from "../input/mathquill-types";
9
+ import {MathFieldActionType} from "../input/mathquill-types";
10
+
11
+ import type Key from "../../data/keys";
12
+ import type {MathFieldInterface} from "../input/mathquill-types";
14
13
 
15
14
  const KeysForJumpContext = {
16
15
  [CursorContext.IN_PARENS]: "JUMP_OUT_PARENTHESES",
@@ -1,16 +1,17 @@
1
- import Key from "../../data/keys";
2
1
  import {DecimalSeparator} from "../../enums";
3
2
  import {decimalSeparator} from "../../utils";
4
3
  import {mathQuillInstance} from "../input/mathquill-instance";
5
- import {
6
- MathFieldInterface,
7
- MathFieldUpdaterCallback,
8
- } from "../input/mathquill-types";
9
4
 
10
5
  import handleArrow from "./handle-arrow";
11
6
  import handleExponent from "./handle-exponent";
12
7
  import handleJumpOut from "./handle-jump-out";
13
8
 
9
+ import type Key from "../../data/keys";
10
+ import type {
11
+ MathFieldInterface,
12
+ MathFieldUpdaterCallback,
13
+ } from "../input/mathquill-types";
14
+
14
15
  enum ActionType {
15
16
  WRITE = "write",
16
17
  CMD = "cmd",
@@ -23,9 +23,10 @@ describe("<KeypadButton />", () => {
23
23
  ).toBeInTheDocument();
24
24
  });
25
25
 
26
- it("handles onClickKey callback", () => {
26
+ it("handles onClickKey callback with click", () => {
27
27
  // Arrange
28
- const mockClickKeyCallback = jest.fn();
28
+ // persist event to prevent React from releasing/nullifying before assertion
29
+ const mockClickKeyCallback = jest.fn((_, event) => event.persist());
29
30
  render(
30
31
  <KeypadButton
31
32
  onClickKey={mockClickKeyCallback}
@@ -38,6 +39,46 @@ describe("<KeypadButton />", () => {
38
39
  userEvent.click(screen.getByRole("button", {name: "Left parenthesis"}));
39
40
 
40
41
  // Assert
41
- expect(mockClickKeyCallback).toHaveBeenCalledWith("LEFT_PAREN");
42
+ expect(mockClickKeyCallback).toHaveBeenCalledWith(
43
+ "LEFT_PAREN",
44
+ expect.objectContaining({
45
+ type: "click",
46
+ detail: 1,
47
+ }),
48
+ );
49
+ });
50
+
51
+ it("handles onClickKey callback with keyboard press", () => {
52
+ // Arrange
53
+ // persist event to prevent React from releasing/nullifying before assertion
54
+ const mockClickKeyCallback = jest.fn((_, event) => event.persist());
55
+ render(
56
+ <KeypadButton
57
+ onClickKey={mockClickKeyCallback}
58
+ keyConfig={Keys.RIGHT_PAREN}
59
+ coord={[0, 0]}
60
+ />,
61
+ );
62
+
63
+ // Act
64
+ screen.getByRole("button", {name: "Right parenthesis"}).focus();
65
+ userEvent.keyboard("{enter}");
66
+
67
+ // Assert
68
+ expect(mockClickKeyCallback).toHaveBeenCalledWith(
69
+ "RIGHT_PAREN",
70
+ // In the browser, "enter" and "space" trigger a click event with detail 0.
71
+ // However, there is a bug in this version (13.5) of RTL that prevents
72
+ // "keypress" from being fired, which handles the click event.
73
+ // https://github.com/testing-library/user-event/blob/5d946d51d643f0ef7e7730fa527b7ca96e330907/src/keyboard/plugins/functional.ts#L99
74
+ // https://github.com/testing-library/user-event/issues/766
75
+ // The only event fired is `keyDown`, which is inconsistent with the
76
+ // browser. If you're reading this and we have upgraded to 14+, please
77
+ // uncomment the `type` assertion below.
78
+ expect.objectContaining({
79
+ // type: "click",
80
+ detail: 0,
81
+ }),
82
+ );
42
83
  });
43
84
  });
@@ -1,4 +1,3 @@
1
- import {PerseusAnalyticsEvent} from "@khanacademy/perseus-core";
2
1
  import Color from "@khanacademy/wonder-blocks-color";
3
2
  import {Popover} from "@khanacademy/wonder-blocks-popover";
4
3
  import {render, screen} from "@testing-library/react";
@@ -7,12 +6,14 @@ import * as React from "react";
7
6
 
8
7
  import "@testing-library/jest-dom";
9
8
 
10
- import Key from "../../../data/keys";
11
9
  import {createMathField} from "../../input/mathquill-instance";
12
- import {MathFieldInterface} from "../../input/mathquill-types";
13
10
  import keyTranslator from "../../key-handlers/key-translator";
14
11
  import Keypad from "../index";
15
12
 
13
+ import type Key from "../../../data/keys";
14
+ import type {MathFieldInterface} from "../../input/mathquill-types";
15
+ import type {PerseusAnalyticsEvent} from "@khanacademy/perseus-core";
16
+
16
17
  type Props = {
17
18
  onChangeMathInput: (mathInputTex: string) => void;
18
19
  keypadClosed?: boolean;
@@ -1,46 +1,16 @@
1
1
  import renderSingleKeypad from "../../../../../../testing/render-keypad-with-cypress";
2
- import KeyConfigs from "../../../data/key-configs";
3
2
 
4
- const tabs = [
5
- {
6
- name: "Operators",
7
- specialButton: "EXP_2",
8
- label: KeyConfigs["EXP_2"].ariaLabel,
9
- },
10
- {name: "Extras", specialButton: "PI", label: KeyConfigs["PI"].ariaLabel},
11
-
12
- {
13
- name: "Geometry",
14
- specialButton: "COS",
15
- label: KeyConfigs["COS"].ariaLabel,
16
- },
17
- {
18
- name: "Numbers",
19
- specialButton: "NUM_7",
20
- label: KeyConfigs["NUM_7"].ariaLabel,
21
- },
22
- ];
3
+ import tabs from "./test-data-tabs";
23
4
 
24
5
  describe("Keypad v2", () => {
25
6
  tabs.forEach((tab) => {
26
7
  it(`switches to the correct tab: ${tab.name}`, () => {
27
- renderSingleKeypad((key) => {});
8
+ renderSingleKeypad();
28
9
 
29
10
  // currently clicking on the bottom left due to button re-rendering
30
11
  // after mousedown but before mouseup (only in Cypress)
31
12
  cy.get('[aria-label="' + tab.name + '"]').click("bottomLeft");
32
13
  cy.get('[aria-label="' + tab.label + '"]').should("exist");
33
14
  });
34
-
35
- it(`calls ${tab.specialButton} key callback in ${tab.name} tab`, () => {
36
- const onClickKeySpy = cy.spy().as("onClickKeySpy");
37
- renderSingleKeypad(onClickKeySpy);
38
- cy.get('[aria-label="' + tab.name + '"]').click();
39
- cy.get('[aria-label="' + tab.label + '"]').click();
40
- cy.get("@onClickKeySpy").should(
41
- "have.been.calledOnceWithExactly",
42
- tab.specialButton,
43
- );
44
- });
45
15
  });
46
16
  });
@@ -1,4 +1,5 @@
1
1
  import {render, screen} from "@testing-library/react";
2
+ import userEvent from "@testing-library/user-event";
2
3
  import * as React from "react";
3
4
  import "@testing-library/jest-dom";
4
5
 
@@ -6,6 +7,8 @@ import keyConfigs from "../../../data/key-configs";
6
7
  import {CursorContext} from "../../input/cursor-contexts";
7
8
  import Keypad from "../index";
8
9
 
10
+ import tabs from "./test-data-tabs";
11
+
9
12
  const contextToKeyAria = {
10
13
  [CursorContext.IN_PARENS]: keyConfigs.JUMP_OUT_PARENTHESES.ariaLabel,
11
14
  [CursorContext.IN_SUPER_SCRIPT]: keyConfigs.JUMP_OUT_EXPONENT.ariaLabel,
@@ -74,4 +77,47 @@ describe("keypad", () => {
74
77
  }),
75
78
  ).not.toBeInTheDocument();
76
79
  });
80
+
81
+ it(`hides the tabs if providing the Fraction Keypad`, () => {
82
+ // Arrange
83
+ // Act
84
+ render(
85
+ <Keypad
86
+ onClickKey={() => {}}
87
+ fractionsOnly={true}
88
+ sendEvent={async () => {}}
89
+ />,
90
+ );
91
+
92
+ // Assert
93
+ expect(screen.queryByRole("tab")).not.toBeInTheDocument();
94
+ });
95
+
96
+ it(`clicking tab triggers callback`, () => {
97
+ // Arrange
98
+ const onClickKey = jest.fn();
99
+
100
+ // Act
101
+ render(
102
+ <Keypad
103
+ onClickKey={onClickKey}
104
+ preAlgebra
105
+ trigonometry
106
+ extraKeys={["PI"]}
107
+ sendEvent={async () => {}}
108
+ />,
109
+ );
110
+
111
+ for (const tabData of tabs) {
112
+ const tab = screen.getByLabelText(tabData.name);
113
+ expect(tab).toBeInTheDocument();
114
+ userEvent.click(tab);
115
+ const key = screen.getByLabelText(tabData.label);
116
+ expect(key).toBeInTheDocument();
117
+ userEvent.click(key);
118
+ }
119
+
120
+ // Assert
121
+ expect(onClickKey).toHaveBeenCalledTimes(tabs.length);
122
+ });
77
123
  });
@@ -0,0 +1,21 @@
1
+ import KeyConfigs from "../../../data/key-configs";
2
+
3
+ export default [
4
+ {
5
+ name: "Operators",
6
+ specialButton: "EXP_2",
7
+ label: KeyConfigs["EXP_2"].ariaLabel,
8
+ },
9
+ {name: "Extras", specialButton: "PI", label: KeyConfigs["PI"].ariaLabel},
10
+
11
+ {
12
+ name: "Geometry",
13
+ specialButton: "COS",
14
+ label: KeyConfigs["COS"].ariaLabel,
15
+ },
16
+ {
17
+ name: "Numbers",
18
+ specialButton: "NUM_7",
19
+ label: KeyConfigs["NUM_7"].ariaLabel,
20
+ },
21
+ ];