@khanacademy/math-input 3.0.0 → 4.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 (91) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/components/input/__tests__/test-math-wrapper.d.ts +1 -1
  3. package/dist/components/input/__tests__/test-math-wrapper.js.flow +1 -1
  4. package/dist/components/input/key-handlers/handle-arrow.d.ts +3 -0
  5. package/dist/components/input/key-handlers/handle-arrow.js.flow +12 -0
  6. package/dist/components/input/key-handlers/handle-backspace.d.ts +7 -0
  7. package/dist/components/input/key-handlers/handle-backspace.js.flow +14 -0
  8. package/dist/components/input/key-handlers/handle-exponent.d.ts +3 -0
  9. package/dist/components/input/key-handlers/handle-exponent.js.flow +12 -0
  10. package/dist/components/input/key-handlers/handle-jump-out.d.ts +7 -0
  11. package/dist/components/input/key-handlers/handle-jump-out.js.flow +14 -0
  12. package/dist/components/input/math-wrapper.d.ts +7 -78
  13. package/dist/components/input/math-wrapper.js.flow +16 -78
  14. package/dist/components/input/mathquill-helpers.d.ts +46 -0
  15. package/dist/components/input/mathquill-helpers.js.flow +56 -0
  16. package/dist/components/input/mathquill-instance.d.ts +3 -0
  17. package/dist/components/input/mathquill-instance.js.flow +9 -0
  18. package/dist/components/input/mathquill-types.d.ts +25 -0
  19. package/dist/components/input/mathquill-types.js.flow +34 -0
  20. package/dist/components/key-translator.d.ts +4 -0
  21. package/dist/components/key-translator.js.flow +10 -0
  22. package/dist/components/keypad/button-assets.d.ts +2 -2
  23. package/dist/components/keypad/button-assets.js.flow +2 -2
  24. package/dist/components/keypad/keypad-page-items.d.ts +1 -1
  25. package/dist/components/keypad/keypad-page-items.js.flow +1 -1
  26. package/dist/components/keypad-legacy/gesture-manager.d.ts +21 -9
  27. package/dist/components/keypad-legacy/gesture-manager.js.flow +27 -12
  28. package/dist/components/keypad-legacy/gesture-state-machine.d.ts +9 -9
  29. package/dist/components/keypad-legacy/gesture-state-machine.js.flow +10 -10
  30. package/dist/components/keypad-legacy/keypad-button.d.ts +2 -2
  31. package/dist/components/keypad-legacy/keypad-button.js.flow +3 -3
  32. package/dist/components/keypad-legacy/store/actions.d.ts +4 -14
  33. package/dist/components/keypad-legacy/store/actions.js.flow +3 -15
  34. package/dist/components/keypad-legacy/store/types.d.ts +2 -2
  35. package/dist/components/keypad-legacy/store/types.js.flow +2 -2
  36. package/dist/components/keypad-legacy/touchable-keypad-button.d.ts +6 -6
  37. package/dist/components/keypad-legacy/touchable-keypad-button.js.flow +9 -14
  38. package/dist/data/key-configs.d.ts +3 -6
  39. package/dist/data/key-configs.js.flow +3 -8
  40. package/dist/data/keys.d.ts +2 -54
  41. package/dist/data/keys.js.flow +116 -55
  42. package/dist/enums.d.ts +2 -9
  43. package/dist/enums.js.flow +2 -11
  44. package/dist/es/index.js +1781 -1196
  45. package/dist/es/index.js.map +1 -1
  46. package/dist/index.d.ts +3 -2
  47. package/dist/index.js +2069 -1242
  48. package/dist/index.js.flow +4 -2
  49. package/dist/index.js.map +1 -1
  50. package/dist/strings.js +26 -10
  51. package/dist/types.d.ts +10 -12
  52. package/dist/types.js.flow +13 -12
  53. package/package.json +1 -1
  54. package/src/components/input/__tests__/context-tracking.test.ts +43 -44
  55. package/src/components/input/__tests__/mathquill.test.ts +133 -135
  56. package/src/components/input/key-handlers/handle-arrow.ts +70 -0
  57. package/src/components/input/key-handlers/handle-backspace.ts +275 -0
  58. package/src/components/input/key-handlers/handle-exponent.ts +52 -0
  59. package/src/components/input/key-handlers/handle-jump-out.ts +103 -0
  60. package/src/components/input/math-input.tsx +11 -12
  61. package/src/components/input/math-wrapper.ts +88 -837
  62. package/src/components/input/mathquill-helpers.ts +268 -0
  63. package/src/components/input/mathquill-instance.ts +5 -0
  64. package/src/components/input/mathquill-types.ts +55 -0
  65. package/src/components/key-translator.ts +209 -0
  66. package/src/components/keypad/button-assets.tsx +411 -100
  67. package/src/components/keypad/geometry-page/index.tsx +1 -1
  68. package/src/components/keypad/keypad-mathquill.stories.tsx +69 -0
  69. package/src/components/keypad/keypad-page-items.tsx +2 -1
  70. package/src/components/keypad/operators-page/index.tsx +1 -1
  71. package/src/components/keypad-legacy/echo-manager.tsx +4 -4
  72. package/src/components/keypad-legacy/empty-keypad-button.tsx +6 -4
  73. package/src/components/keypad-legacy/gesture-manager.ts +32 -9
  74. package/src/components/keypad-legacy/gesture-state-machine.ts +14 -14
  75. package/src/components/keypad-legacy/keypad-button.tsx +15 -18
  76. package/src/components/keypad-legacy/many-keypad-button.tsx +9 -2
  77. package/src/components/keypad-legacy/store/actions.ts +3 -29
  78. package/src/components/keypad-legacy/store/echo-reducer.ts +2 -5
  79. package/src/components/keypad-legacy/store/index.ts +4 -10
  80. package/src/components/keypad-legacy/store/input-reducer.ts +1 -2
  81. package/src/components/keypad-legacy/store/keypad-reducer.ts +2 -3
  82. package/src/components/keypad-legacy/store/types.ts +2 -2
  83. package/src/components/keypad-legacy/touchable-keypad-button.tsx +8 -13
  84. package/src/components/tabbar/icons.tsx +0 -2
  85. package/src/data/key-configs.ts +751 -304
  86. package/src/data/keys.ts +118 -65
  87. package/src/enums.ts +10 -9
  88. package/src/index.ts +3 -2
  89. package/src/math-input.stories.tsx +1 -1
  90. package/src/types.ts +10 -12
  91. package/tsconfig-build.tsbuildinfo +1 -1
@@ -0,0 +1,69 @@
1
+ import MathQuill from "mathquill";
2
+ import * as React from "react";
3
+
4
+ import Key from "../../data/keys";
5
+ import keyTranslator from "../key-translator";
6
+
7
+ import Keypad from "./index";
8
+
9
+ export default {
10
+ title: "v2 Keypad With Mathquill",
11
+ };
12
+
13
+ const mathQuillConfig = {
14
+ autoCommands: "pi theta phi sqrt nthroot",
15
+ charsThatBreakOutOfSupSub: "+-*/=<>≠≤≥",
16
+ supSubsRequireOperand: true,
17
+ spaceBehavesLikeTab: true,
18
+ };
19
+
20
+ export function V2KeypadWithMathquill() {
21
+ const mathquillWrapperRef = React.useRef<HTMLDivElement>(null);
22
+ const [mathQuill, setMathQuill] = React.useState<MathQuill>();
23
+
24
+ React.useEffect(() => {
25
+ if (!mathQuill && mathquillWrapperRef.current) {
26
+ const MQ = MathQuill.getInterface(2);
27
+ const mathQuillInstance = MQ.MathField(
28
+ mathquillWrapperRef.current,
29
+ mathQuillConfig,
30
+ );
31
+ setMathQuill(mathQuillInstance);
32
+ }
33
+ }, [mathQuill]);
34
+
35
+ function handleClickKey(key: Key) {
36
+ if (!mathQuill) {
37
+ return;
38
+ }
39
+
40
+ const mathQuillCallback = keyTranslator[key];
41
+ if (mathQuillCallback) {
42
+ mathQuillCallback(mathQuill, key);
43
+ } else {
44
+ // eslint-disable-next-line no-console
45
+ console.warn(`No translation to Mathquill for: ${key}`);
46
+ }
47
+ }
48
+
49
+ return (
50
+ <div style={{maxWidth: "400px", margin: "2em"}}>
51
+ <div
52
+ ref={mathquillWrapperRef}
53
+ style={{width: "100%", marginBottom: "1em"}}
54
+ />
55
+ <div>
56
+ <Keypad
57
+ onClickKey={handleClickKey}
58
+ advancedRelations
59
+ basicRelations
60
+ divisionKey
61
+ logarithms
62
+ multiplicationDot
63
+ preAlgebra
64
+ trigonometry
65
+ />
66
+ </div>
67
+ </div>
68
+ );
69
+ }
@@ -1,10 +1,11 @@
1
1
  import {View} from "@khanacademy/wonder-blocks-core";
2
2
  import * as React from "react";
3
3
 
4
+ import {KeyConfig} from "../../types";
5
+
4
6
  import Button from "./button";
5
7
  import ButtonAsset from "./button-assets";
6
8
 
7
- import type {KeyConfig} from "../../data/key-configs";
8
9
  import type {StyleType} from "@khanacademy/wonder-blocks-core";
9
10
 
10
11
  type KeypadPageContainerProps = {
@@ -42,7 +42,7 @@ export default class OperatorsPage extends React.Component<Props> {
42
42
  placeholder={!this.props.logarithms}
43
43
  />
44
44
  <SecondaryKeypadButton
45
- keyConfig={Keys.X}
45
+ keyConfig={Keys.x}
46
46
  onClickKey={onClickKey}
47
47
  style={{
48
48
  gridColumn: 5,
@@ -6,8 +6,8 @@ import * as React from "react";
6
6
  import {TransitionGroup, CSSTransition} from "react-transition-group";
7
7
 
8
8
  import KeyConfigs from "../../data/key-configs";
9
- import Keys from "../../data/keys";
10
- import {KeyType, EchoAnimationType} from "../../enums";
9
+ import Key from "../../data/keys";
10
+ import {EchoAnimationType} from "../../enums";
11
11
 
12
12
  import KeypadButton from "./keypad-button";
13
13
  import * as zIndexes from "./z-indexes";
@@ -16,7 +16,7 @@ import type {Bound, Echo as EchoType} from "../../types";
16
16
 
17
17
  type EchoProps = {
18
18
  animationDurationMs: number;
19
- id: Keys;
19
+ id: Key;
20
20
  initialBounds: Bound;
21
21
  onAnimationFinish: () => void;
22
22
  };
@@ -50,7 +50,7 @@ class Echo extends React.Component<EchoProps> {
50
50
  // applied via StyleSheet, will override our inlines.
51
51
  return (
52
52
  <div style={containerStyle}>
53
- <KeypadButton icon={icon} type={KeyType.ECHO} />
53
+ <KeypadButton icon={icon} type={"ECHO"} />
54
54
  </div>
55
55
  );
56
56
  }
@@ -27,14 +27,16 @@ class EmptyKeypadButton extends React.Component<ReduxProps> {
27
27
  // to focus them or trigger presses.
28
28
  return (
29
29
  <KeypadButton
30
- onTouchStart={(evt: TouchEvent) =>
30
+ onTouchStart={(evt: React.TouchEvent<HTMLDivElement>) =>
31
31
  gestureManager.onTouchStart(evt)
32
32
  }
33
- onTouchEnd={(evt: TouchEvent) => gestureManager.onTouchEnd(evt)}
34
- onTouchMove={(evt: TouchEvent) =>
33
+ onTouchEnd={(evt: React.TouchEvent<HTMLDivElement>) =>
34
+ gestureManager.onTouchEnd(evt)
35
+ }
36
+ onTouchMove={(evt: React.TouchEvent<HTMLDivElement>) =>
35
37
  gestureManager.onTouchMove(evt)
36
38
  }
37
- onTouchCancel={(evt: TouchEvent) =>
39
+ onTouchCancel={(evt: React.TouchEvent<HTMLDivElement>) =>
38
40
  gestureManager.onTouchCancel(evt)
39
41
  }
40
42
  {...KeyConfigs.NOOP}
@@ -3,6 +3,10 @@
3
3
  * connects our various bits of logic for managing gestures and interactions,
4
4
  * and links them together.
5
5
  */
6
+ import * as React from "react";
7
+
8
+ import Key from "../../data/keys";
9
+ import {ActiveNodesObj, LayoutProps} from "../../types";
6
10
 
7
11
  import GestureStateMachine from "./gesture-state-machine";
8
12
  import NodeManager from "./node-manager";
@@ -12,6 +16,17 @@ const coordsForEvent = (evt) => {
12
16
  return [evt.changedTouches[0].clientX, evt.changedTouches[0].clientY];
13
17
  };
14
18
 
19
+ type Options = {
20
+ swipeEnabled: boolean;
21
+ };
22
+
23
+ type Handlers = {
24
+ onSwipeChange?: (dx: number) => void;
25
+ onSwipeEnd?: (dx: number) => void;
26
+ onActiveNodesChanged: (activeNodes: ActiveNodesObj) => void;
27
+ onClick: (key: Key, layoutProps: LayoutProps, inPopover: boolean) => void;
28
+ };
29
+
15
30
  class GestureManager {
16
31
  swipeEnabled: boolean;
17
32
  trackEvents: boolean;
@@ -19,7 +34,12 @@ class GestureManager {
19
34
  popoverStateMachine: PopoverStateMachine;
20
35
  gestureStateMachine: GestureStateMachine;
21
36
 
22
- constructor(options, handlers, disabledSwipeKeys, multiPressableKeys) {
37
+ constructor(
38
+ options: Options,
39
+ handlers: Handlers,
40
+ disabledSwipeKeys: ReadonlyArray<Key>,
41
+ multiPressableKeys: ReadonlyArray<Key>,
42
+ ) {
23
43
  const {swipeEnabled} = options;
24
44
 
25
45
  this.swipeEnabled = swipeEnabled;
@@ -96,11 +116,14 @@ class GestureManager {
96
116
  * Handle a touch-start event that originated in a node registered with the
97
117
  * gesture system.
98
118
  *
99
- * @param {TouchEvent} evt - the raw touch event from the browser
119
+ * @param {React.TouchEvent<HTMLDivElement>} evt - the raw touch event from the browser
100
120
  * @param {string} id - the identifier of the DOM node in which the touch
101
121
  * occurred
102
122
  */
103
- onTouchStart(evt: TouchEvent, id?) {
123
+ onTouchStart(
124
+ evt: React.TouchEvent<HTMLDivElement>,
125
+ id?: string | undefined,
126
+ ) {
104
127
  if (!this.trackEvents) {
105
128
  return;
106
129
  }
@@ -128,9 +151,9 @@ class GestureManager {
128
151
  * Handle a touch-move event that originated in a node registered with the
129
152
  * gesture system.
130
153
  *
131
- * @param {TouchEvent} evt - the raw touch event from the browser
154
+ * @param {React.TouchEvent<HTMLDivElement>} evt - the raw touch event from the browser
132
155
  */
133
- onTouchMove(evt: TouchEvent) {
156
+ onTouchMove(evt: React.TouchEvent<HTMLDivElement>) {
134
157
  if (!this.trackEvents) {
135
158
  return;
136
159
  }
@@ -152,9 +175,9 @@ class GestureManager {
152
175
  * Handle a touch-end event that originated in a node registered with the
153
176
  * gesture system.
154
177
  *
155
- * @param {TouchEvent} evt - the raw touch event from the browser
178
+ * @param {React.TouchEvent<HTMLDivElement>} evt - the raw touch event from the browser
156
179
  */
157
- onTouchEnd(evt: TouchEvent) {
180
+ onTouchEnd(evt: React.TouchEvent<HTMLDivElement>) {
158
181
  if (!this.trackEvents) {
159
182
  return;
160
183
  }
@@ -173,9 +196,9 @@ class GestureManager {
173
196
  * Handle a touch-cancel event that originated in a node registered with the
174
197
  * gesture system.
175
198
  *
176
- * @param {TouchEvent} evt - the raw touch event from the browser
199
+ * @param {React.TouchEvent<HTMLDivElement>} evt - the raw touch event from the browser
177
200
  */
178
- onTouchCancel(evt: TouchEvent) {
201
+ onTouchCancel(evt: React.TouchEvent<HTMLDivElement>) {
179
202
  if (!this.trackEvents) {
180
203
  return;
181
204
  }
@@ -1,4 +1,4 @@
1
- import Keys from "../../data/keys";
1
+ import Key from "../../data/keys";
2
2
 
3
3
  /**
4
4
  * The state machine that backs our gesture system. In particular, this state
@@ -14,8 +14,8 @@ export type Handlers = {
14
14
  onBlur: () => void;
15
15
  onTrigger: (id: string) => void;
16
16
  onLongPress: (id: string) => void;
17
- onSwipeChange: (x: number) => void;
18
- onSwipeEnd: (x: number) => void;
17
+ onSwipeChange?: (x: number) => void;
18
+ onSwipeEnd?: (x: number) => void;
19
19
  onTouchEnd: (id: string) => void;
20
20
  };
21
21
 
@@ -26,17 +26,17 @@ type Options = {
26
26
  };
27
27
 
28
28
  type TouchState = {
29
- activeNodeId: Keys;
29
+ activeNodeId: Key;
30
30
  pressAndHoldIntervalId: number | null;
31
31
  longPressTimeoutId: number | null;
32
32
  swipeLocked: boolean;
33
33
  startX: number;
34
34
  };
35
35
 
36
- type TouchStateMap = Record<Keys, TouchState>;
36
+ type TouchStateMap = Record<Key, TouchState>;
37
37
 
38
38
  type SwipeState = {
39
- touchId: Keys;
39
+ touchId: Key;
40
40
  startX: number;
41
41
  };
42
42
 
@@ -49,16 +49,16 @@ const defaultOptions: Options = {
49
49
  class GestureStateMachine {
50
50
  handlers: Handlers;
51
51
  options: Options;
52
- swipeDisabledNodeIds: Partial<[Keys]>;
53
- multiPressableKeys: Partial<[Keys]>;
52
+ swipeDisabledNodeIds: ReadonlyArray<Key>;
53
+ multiPressableKeys: ReadonlyArray<Key>;
54
54
  touchState: Partial<TouchStateMap>;
55
55
  swipeState: SwipeState | null;
56
56
 
57
57
  constructor(
58
58
  handlers: Handlers,
59
59
  options: Partial<Options>,
60
- swipeDisabledNodeIds?: [Keys],
61
- multiPressableKeys?: [Keys],
60
+ swipeDisabledNodeIds?: ReadonlyArray<Key>,
61
+ multiPressableKeys?: ReadonlyArray<Key>,
62
62
  ) {
63
63
  this.handlers = handlers;
64
64
  this.options = {
@@ -234,7 +234,7 @@ class GestureStateMachine {
234
234
  // Only respect the finger that started a swipe. Any other lingering
235
235
  // gestures are ignored.
236
236
  if (this.swipeState.touchId === touchId) {
237
- this.handlers.onSwipeChange(pageX - this.swipeState.startX);
237
+ this.handlers.onSwipeChange?.(pageX - this.swipeState.startX);
238
238
  }
239
239
  } else if (this.touchState[touchId]) {
240
240
  // It could be touch events started outside the keypad and
@@ -256,7 +256,7 @@ class GestureStateMachine {
256
256
  touchId,
257
257
  startX,
258
258
  };
259
- this.handlers.onSwipeChange(pageX - this.swipeState.startX);
259
+ this.handlers.onSwipeChange?.(pageX - this.swipeState.startX);
260
260
  } else {
261
261
  const id = getId();
262
262
  if (id !== activeNodeId) {
@@ -279,7 +279,7 @@ class GestureStateMachine {
279
279
  // Only respect the finger that started a swipe. Any other lingering
280
280
  // gestures are ignored.
281
281
  if (this.swipeState.touchId === touchId) {
282
- this.handlers.onSwipeEnd(pageX - this.swipeState.startX);
282
+ this.handlers.onSwipeEnd?.(pageX - this.swipeState.startX);
283
283
  this.swipeState = null;
284
284
  }
285
285
  } else if (this.touchState[touchId]) {
@@ -313,7 +313,7 @@ class GestureStateMachine {
313
313
  // displacement.
314
314
  if (this.swipeState) {
315
315
  if (this.swipeState.touchId === touchId) {
316
- this.handlers.onSwipeEnd(0);
316
+ this.handlers.onSwipeEnd?.(0);
317
317
  this.swipeState = null;
318
318
  }
319
319
  } else if (this.touchState[touchId]) {
@@ -6,7 +6,7 @@ import {StyleSheet, css} from "aphrodite";
6
6
  import * as React from "react";
7
7
  import {connect} from "react-redux";
8
8
 
9
- import {BorderDirection, BorderStyles, KeyType} from "../../enums";
9
+ import {BorderDirection, BorderStyles, KeyType, KeyTypes} from "../../enums";
10
10
  import {View} from "../../fake-react-native-web/index";
11
11
  import {
12
12
  wonderBlocksBlue,
@@ -40,7 +40,7 @@ interface Props extends ReduxProps {
40
40
  focused: boolean;
41
41
  popoverEnabled: boolean;
42
42
  type: KeyType;
43
- icon: IconConfig;
43
+ icon?: IconConfig;
44
44
  style?: StyleType;
45
45
  onTouchCancel?: (evt: React.TouchEvent<HTMLDivElement>) => void;
46
46
  onTouchEnd?: (evt: React.TouchEvent<HTMLDivElement>) => void;
@@ -101,7 +101,7 @@ class KeypadButton extends React.PureComponent<Props> {
101
101
  // object. This method must be called whenever a property that
102
102
  // influences the possible outcomes of `this._getFocusStyle` and
103
103
  // `this._getButtonStyle` changes (such as `this.buttonSizeStyle`).
104
- for (const type of Object.values(KeyType)) {
104
+ for (const type of KeyTypes) {
105
105
  css(View.styles.initial, ...this._getFocusStyle(type));
106
106
 
107
107
  for (const borders of Object.values(BorderStyles)) {
@@ -115,10 +115,7 @@ class KeypadButton extends React.PureComponent<Props> {
115
115
 
116
116
  _getFocusStyle = (type: KeyType) => {
117
117
  let focusBackgroundStyle;
118
- if (
119
- type === KeyType.INPUT_NAVIGATION ||
120
- type === KeyType.KEYPAD_NAVIGATION
121
- ) {
118
+ if (type === "INPUT_NAVIGATION" || type === "KEYPAD_NAVIGATION") {
122
119
  focusBackgroundStyle = styles.light;
123
120
  } else {
124
121
  focusBackgroundStyle = styles.bright;
@@ -131,25 +128,25 @@ class KeypadButton extends React.PureComponent<Props> {
131
128
  // Select the appropriate style for the button.
132
129
  let backgroundStyle;
133
130
  switch (type) {
134
- case KeyType.EMPTY:
131
+ case "EMPTY":
135
132
  backgroundStyle = styles.empty;
136
133
  break;
137
134
 
138
- case KeyType.MANY:
139
- case KeyType.VALUE:
135
+ case "MANY":
136
+ case "VALUE":
140
137
  backgroundStyle = styles.value;
141
138
  break;
142
139
 
143
- case KeyType.OPERATOR:
140
+ case "OPERATOR":
144
141
  backgroundStyle = styles.operator;
145
142
  break;
146
143
 
147
- case KeyType.INPUT_NAVIGATION:
148
- case KeyType.KEYPAD_NAVIGATION:
144
+ case "INPUT_NAVIGATION":
145
+ case "KEYPAD_NAVIGATION":
149
146
  backgroundStyle = styles.control;
150
147
  break;
151
148
 
152
- case KeyType.ECHO:
149
+ case "ECHO":
153
150
  backgroundStyle = null;
154
151
  break;
155
152
  }
@@ -168,7 +165,7 @@ class KeypadButton extends React.PureComponent<Props> {
168
165
  styles.buttonBase,
169
166
  backgroundStyle,
170
167
  ...borderStyle,
171
- type === KeyType.ECHO && styles.echo,
168
+ type === "ECHO" && styles.echo,
172
169
  this.buttonSizeStyle,
173
170
  // React Native allows you to set the 'style' props on user defined
174
171
  // components.
@@ -197,7 +194,7 @@ class KeypadButton extends React.PureComponent<Props> {
197
194
  // We render in the focus state if the key is focused, or if it's an
198
195
  // echo.
199
196
  const renderFocused =
200
- (!disabled && focused) || popoverEnabled || type === KeyType.ECHO;
197
+ (!disabled && focused) || popoverEnabled || type === "ECHO";
201
198
  const buttonStyle = this._getButtonStyle(type, borders, style);
202
199
  const focusStyle = this._getFocusStyle(type);
203
200
  const iconWrapperStyle = [
@@ -218,9 +215,9 @@ class KeypadButton extends React.PureComponent<Props> {
218
215
  childKeys &&
219
216
  childKeys.length > 0 && <CornerDecal style={styles.decalInset} />;
220
217
 
221
- if (type === KeyType.EMPTY) {
218
+ if (type === "EMPTY") {
222
219
  return <View style={buttonStyle} {...eventHandlers} />;
223
- } else if (type === KeyType.MANY) {
220
+ } else if (type === "MANY") {
224
221
  // TODO(charlie): Make the long-press interaction accessible. See
225
222
  // the TODO in key-configs.js for more.
226
223
  const manyButtonA11yMarkup = {
@@ -6,7 +6,7 @@
6
6
  import * as React from "react";
7
7
 
8
8
  import KeyConfigs from "../../data/key-configs";
9
- import {KeyType} from "../../enums";
9
+ import {IconType} from "../../enums";
10
10
  import {KeyConfig} from "../../types";
11
11
 
12
12
  import EmptyKeypadButton from "./empty-keypad-button";
@@ -35,8 +35,15 @@ class ManyKeypadButton extends React.Component<Props> {
35
35
  } else {
36
36
  const keyConfig: KeyConfig = {
37
37
  id: "MANY",
38
- type: KeyType.MANY,
38
+ type: "MANY",
39
39
  childKeyIds: keys,
40
+ ariaLabel: keys
41
+ .map((key) => KeyConfigs[key].ariaLabel)
42
+ .join(", "),
43
+ icon: {
44
+ type: IconType.SVG,
45
+ data: "many",
46
+ },
40
47
  };
41
48
  return <TouchableKeypadButton keyConfig={keyConfig} {...rest} />;
42
49
  }
@@ -1,4 +1,4 @@
1
- import Keys from "../../../data/keys";
1
+ import Key from "../../../data/keys";
2
2
 
3
3
  import type {
4
4
  Bound,
@@ -104,30 +104,6 @@ export const setCursor = (cursor: Cursor): SetCursorAction => {
104
104
  };
105
105
 
106
106
  // Gesture actions
107
- type OnSwipeChangeAction = {
108
- type: "OnSwipeChange";
109
- dx: number;
110
- };
111
-
112
- export const onSwipeChange = (dx: number): OnSwipeChangeAction => {
113
- return {
114
- type: "OnSwipeChange",
115
- dx,
116
- };
117
- };
118
-
119
- type OnSwipeEndAction = {
120
- type: "OnSwipeEnd";
121
- dx: number;
122
- };
123
-
124
- export const onSwipeEnd = (dx: number): OnSwipeEndAction => {
125
- return {
126
- type: "OnSwipeEnd",
127
- dx,
128
- };
129
- };
130
-
131
107
  type SetActiveNodesAction = {
132
108
  type: "SetActiveNodes";
133
109
  activeNodes: any;
@@ -144,13 +120,13 @@ export const setActiveNodes = (
144
120
 
145
121
  type PressKeyAction = {
146
122
  type: "PressKey";
147
- key: Keys;
123
+ key: Key;
148
124
  initialBounds: Bound;
149
125
  inPopover: boolean;
150
126
  };
151
127
 
152
128
  export const pressKey = (
153
- key: Keys,
129
+ key: Key,
154
130
  initialBounds: Bound,
155
131
  inPopover: any,
156
132
  ): PressKeyAction => {
@@ -170,7 +146,5 @@ export type Action =
170
146
  | RemoveEchoAction
171
147
  | SetKeyHandlerAction
172
148
  | SetCursorAction
173
- | OnSwipeChangeAction
174
- | OnSwipeEndAction
175
149
  | SetActiveNodesAction
176
150
  | PressKeyAction;
@@ -1,5 +1,5 @@
1
1
  import KeyConfigs from "../../../data/key-configs";
2
- import {EchoAnimationType, KeyType} from "../../../enums";
2
+ import {EchoAnimationType} from "../../../enums";
3
3
 
4
4
  import type {Action} from "./actions";
5
5
  import type {EchoState} from "./types";
@@ -22,10 +22,7 @@ const echoReducer = function (
22
22
 
23
23
  // Add in the echo animation if the user performs a math
24
24
  // operation.
25
- if (
26
- keyConfig.type === KeyType.VALUE ||
27
- keyConfig.type === KeyType.OPERATOR
28
- ) {
25
+ if (keyConfig.type === "VALUE" || keyConfig.type === "OPERATOR") {
29
26
  return {
30
27
  ...state,
31
28
  echoes: [
@@ -1,9 +1,9 @@
1
1
  import * as Redux from "redux";
2
2
 
3
- import Keys from "../../../data/keys";
3
+ import Key from "../../../data/keys";
4
4
  import GestureManager from "../gesture-manager";
5
5
 
6
- import {onSwipeChange, onSwipeEnd, setActiveNodes, pressKey} from "./actions";
6
+ import {setActiveNodes, pressKey} from "./actions";
7
7
  import echoReducer from "./echo-reducer";
8
8
  import inputReducer from "./input-reducer";
9
9
  import keypadReducer from "./keypad-reducer";
@@ -23,17 +23,11 @@ export const createStore = () => {
23
23
  swipeEnabled,
24
24
  },
25
25
  {
26
- onSwipeChange: (dx: number) => {
27
- store.dispatch(onSwipeChange(dx));
28
- },
29
- onSwipeEnd: (dx: number) => {
30
- store.dispatch(onSwipeEnd(dx));
31
- },
32
26
  onActiveNodesChanged: (activeNodes: ActiveNodesObj) => {
33
27
  store.dispatch(setActiveNodes(activeNodes));
34
28
  },
35
29
  onClick: (
36
- key: Keys,
30
+ key: Key,
37
31
  layoutProps: LayoutProps,
38
32
  inPopover: boolean,
39
33
  ) => {
@@ -43,7 +37,7 @@ export const createStore = () => {
43
37
  },
44
38
  },
45
39
  [],
46
- [Keys.BACKSPACE, Keys.UP, Keys.RIGHT, Keys.DOWN, Keys.LEFT],
40
+ ["BACKSPACE", "UP", "RIGHT", "DOWN", "LEFT"],
47
41
  );
48
42
  };
49
43
 
@@ -1,5 +1,4 @@
1
1
  import KeyConfigs from "../../../data/key-configs";
2
- import {KeyType} from "../../../enums";
3
2
  import {CursorContext} from "../../input/cursor-contexts";
4
3
 
5
4
  import type {Cursor, KeyHandler} from "../../../types";
@@ -29,7 +28,7 @@ const inputReducer = function (
29
28
 
30
29
  case "PressKey":
31
30
  const keyConfig = KeyConfigs[action.key];
32
- if (keyConfig.type !== KeyType.KEYPAD_NAVIGATION) {
31
+ if (keyConfig.type !== "KEYPAD_NAVIGATION") {
33
32
  // This is probably an anti-pattern but it works for the
34
33
  // case where we don't actually control the state but we
35
34
  // still want to communicate with the other object
@@ -1,5 +1,4 @@
1
1
  import KeyConfigs from "../../../data/key-configs";
2
- import Keys from "../../../data/keys";
3
2
 
4
3
  import {defaultKeypadType} from "./shared";
5
4
 
@@ -7,7 +6,7 @@ import type {Action} from "./actions";
7
6
  import type {KeypadState} from "./types";
8
7
 
9
8
  const initialKeypadState = {
10
- extraKeys: ["x", "y", Keys.THETA, Keys.PI],
9
+ extraKeys: ["x", "y", "THETA", "PI"] as const,
11
10
  keypadType: defaultKeypadType,
12
11
  active: false,
13
12
  } as const;
@@ -46,7 +45,7 @@ const keypadReducer = function (
46
45
  // right actions when they occur. Hence, we figure off a
47
46
  // dismissal here rather than dispatching a dismiss action in
48
47
  // the first place.
49
- if (keyConfig.id === Keys.DISMISS) {
48
+ if (keyConfig.id === "DISMISS") {
50
49
  return keypadReducer(state, {type: "DismissKeypad"});
51
50
  }
52
51
  return state;
@@ -1,4 +1,4 @@
1
- import Keys from "../../../data/keys";
1
+ import Key from "../../../data/keys";
2
2
  import {LayoutMode, KeypadType} from "../../../enums";
3
3
  import GestureManager from "../gesture-manager";
4
4
 
@@ -36,7 +36,7 @@ export interface GestureState {
36
36
  // The current multikey popover?
37
37
  popover: Popover | null;
38
38
  // ?? Maybe which key is currently focused?
39
- focus: Keys | null;
39
+ focus: Key | null;
40
40
  // Complex object that interprets touches as actions
41
41
  gestureManager: GestureManager;
42
42
  }