@khanacademy/math-input 0.7.2 → 1.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 (176) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/actions/index.d.ts +31 -0
  3. package/dist/actions/index.js.flow +40 -0
  4. package/dist/components/compute-layout-parameters.d.ts +38 -0
  5. package/dist/components/compute-layout-parameters.js.flow +49 -0
  6. package/dist/components/corner-decal.d.ts +12 -0
  7. package/dist/components/corner-decal.js.flow +15 -0
  8. package/dist/components/echo-manager.d.ts +26 -0
  9. package/dist/components/echo-manager.js.flow +29 -0
  10. package/dist/components/empty-keypad-button.d.ts +13 -0
  11. package/dist/components/empty-keypad-button.js.flow +23 -0
  12. package/dist/components/expression-keypad.d.ts +22 -0
  13. package/dist/components/expression-keypad.js.flow +32 -0
  14. package/dist/components/fraction-keypad.d.ts +21 -0
  15. package/dist/components/fraction-keypad.js.flow +30 -0
  16. package/dist/components/gesture-manager.d.ts +74 -0
  17. package/dist/components/gesture-manager.js.flow +82 -0
  18. package/dist/components/gesture-state-machine.d.ts +105 -0
  19. package/dist/components/gesture-state-machine.js.flow +118 -0
  20. package/dist/components/icon.d.ts +15 -0
  21. package/dist/components/icon.js.flow +18 -0
  22. package/dist/components/input/__tests__/test-math-wrapper.d.ts +8 -0
  23. package/dist/components/input/__tests__/test-math-wrapper.js.flow +14 -0
  24. package/dist/components/input/cursor-handle.d.ts +1 -1
  25. package/dist/components/input/cursor-handle.js.flow +1 -1
  26. package/dist/components/input/drag-listener.d.ts +13 -0
  27. package/dist/components/input/drag-listener.js.flow +19 -0
  28. package/dist/components/input/math-input.d.ts +5 -4
  29. package/dist/components/input/math-input.js.flow +5 -4
  30. package/dist/components/input/math-wrapper.d.ts +110 -0
  31. package/dist/components/input/math-wrapper.js.flow +125 -0
  32. package/dist/components/input/scroll-into-view.d.ts +11 -0
  33. package/dist/components/input/scroll-into-view.js.flow +20 -0
  34. package/dist/components/keypad/button-assets.d.ts +4 -3
  35. package/dist/components/keypad/button-assets.js.flow +3 -3
  36. package/dist/components/keypad/button.d.ts +1 -2
  37. package/dist/components/keypad/button.js.flow +1 -2
  38. package/dist/components/keypad/keypad-page-items.d.ts +15 -10
  39. package/dist/components/keypad/keypad-page-items.js.flow +20 -10
  40. package/dist/components/keypad-button.d.ts +52 -0
  41. package/dist/components/keypad-button.js.flow +79 -0
  42. package/dist/components/keypad-container.d.ts +40 -0
  43. package/dist/components/keypad-container.js.flow +58 -0
  44. package/dist/components/keypad.d.ts +31 -0
  45. package/dist/components/keypad.js.flow +40 -0
  46. package/dist/components/many-keypad-button.d.ts +15 -0
  47. package/dist/components/many-keypad-button.js.flow +17 -0
  48. package/dist/components/math-icon.d.ts +16 -0
  49. package/dist/components/math-icon.js.flow +19 -0
  50. package/dist/components/multi-symbol-grid.d.ts +14 -0
  51. package/dist/components/multi-symbol-grid.js.flow +16 -0
  52. package/dist/components/multi-symbol-popover.d.ts +12 -0
  53. package/dist/components/multi-symbol-popover.js.flow +15 -0
  54. package/dist/components/navigation-pad.d.ts +14 -0
  55. package/dist/components/navigation-pad.js.flow +16 -0
  56. package/dist/components/node-manager.d.ts +53 -0
  57. package/dist/components/node-manager.js.flow +65 -0
  58. package/dist/components/popover-manager.d.ts +13 -0
  59. package/dist/components/popover-manager.js.flow +15 -0
  60. package/dist/components/popover-state-machine.d.ts +75 -0
  61. package/dist/components/popover-state-machine.js.flow +83 -0
  62. package/dist/components/provided-keypad.d.ts +8 -7
  63. package/dist/components/provided-keypad.js.flow +8 -7
  64. package/dist/components/styles.d.ts +6 -0
  65. package/dist/components/styles.js.flow +13 -0
  66. package/dist/components/svg-icon.d.ts +12 -0
  67. package/dist/components/svg-icon.js.flow +15 -0
  68. package/dist/components/tabbar/icons.d.ts +3 -2
  69. package/dist/components/tabbar/icons.js.flow +3 -2
  70. package/dist/components/tabbar/item.d.ts +1 -2
  71. package/dist/components/tabbar/item.js.flow +1 -2
  72. package/dist/components/tabbar/tabbar.d.ts +3 -3
  73. package/dist/components/tabbar/tabbar.js.flow +3 -3
  74. package/dist/components/text-icon.d.ts +13 -0
  75. package/dist/components/text-icon.js.flow +16 -0
  76. package/dist/components/touchable-keypad-button.d.ts +30 -0
  77. package/dist/components/touchable-keypad-button.js.flow +35 -0
  78. package/dist/components/two-page-keypad.d.ts +20 -0
  79. package/dist/components/two-page-keypad.js.flow +30 -0
  80. package/dist/components/velocity-tracker.d.ts +48 -0
  81. package/dist/components/velocity-tracker.js.flow +54 -0
  82. package/dist/es/index.js +938 -1059
  83. package/dist/es/index.js.map +1 -1
  84. package/dist/fake-react-native-web/text.d.ts +2 -1
  85. package/dist/fake-react-native-web/text.js.flow +2 -1
  86. package/dist/fake-react-native-web/view.d.ts +3 -2
  87. package/dist/fake-react-native-web/view.js.flow +3 -2
  88. package/dist/index.d.ts +1 -1
  89. package/dist/index.js +988 -1089
  90. package/dist/index.js.flow +1 -4
  91. package/dist/index.js.map +1 -1
  92. package/dist/store/echo-reducer.d.ts +5 -0
  93. package/dist/store/echo-reducer.js.flow +14 -0
  94. package/dist/store/index.d.ts +46 -1
  95. package/dist/store/index.js.flow +64 -1
  96. package/dist/store/input-reducer.d.ts +7 -0
  97. package/dist/store/input-reducer.js.flow +16 -0
  98. package/dist/store/keypad-reducer.d.ts +9 -0
  99. package/dist/store/keypad-reducer.js.flow +18 -0
  100. package/dist/store/layout-reducer.d.ts +21 -0
  101. package/dist/store/layout-reducer.js.flow +30 -0
  102. package/dist/store/pager-reducer.d.ts +13 -0
  103. package/dist/store/pager-reducer.js.flow +22 -0
  104. package/dist/store/shared.d.ts +6 -0
  105. package/dist/store/shared.js.flow +13 -0
  106. package/dist/store/types.d.ts +57 -0
  107. package/dist/store/types.js.flow +63 -0
  108. package/dist/types.d.ts +50 -0
  109. package/dist/types.js.flow +61 -0
  110. package/package.json +1 -1
  111. package/src/actions/{index.js → index.ts} +5 -5
  112. package/src/components/__tests__/{gesture-state-machine_test.js → gesture-state-machine.test.ts} +5 -1
  113. package/src/components/__tests__/{two-page-keypad_test.js → two-page-keypad.test.tsx} +0 -2
  114. package/src/components/{corner-decal.js → corner-decal.tsx} +6 -5
  115. package/src/components/{echo-manager.js → echo-manager.tsx} +29 -24
  116. package/src/components/{empty-keypad-button.js → empty-keypad-button.tsx} +17 -10
  117. package/src/components/{expression-keypad.js → expression-keypad.tsx} +27 -25
  118. package/src/components/{fraction-keypad.js → fraction-keypad.tsx} +21 -16
  119. package/src/components/{gesture-manager.js → gesture-manager.tsx} +10 -4
  120. package/src/components/{gesture-state-machine.js → gesture-state-machine.ts} +49 -3
  121. package/src/components/{icon.js → icon.tsx} +12 -14
  122. package/src/components/input/cursor-handle.tsx +1 -1
  123. package/src/components/input/{drag-listener.js → drag-listener.ts} +4 -0
  124. package/src/components/input/math-input.tsx +10 -9
  125. package/src/components/input/{math-wrapper.js → math-wrapper.ts} +10 -6
  126. package/src/components/input/{scroll-into-view.js → scroll-into-view.ts} +5 -15
  127. package/src/components/keypad/button-assets.tsx +4 -5
  128. package/src/components/keypad/button.tsx +1 -2
  129. package/src/components/keypad/index.tsx +1 -1
  130. package/src/components/keypad/keypad-page-items.tsx +33 -10
  131. package/src/components/{keypad-button.js → keypad-button.tsx} +42 -37
  132. package/src/components/{keypad-container.js → keypad-container.tsx} +41 -23
  133. package/src/components/{keypad.js → keypad.tsx} +31 -23
  134. package/src/components/{many-keypad-button.js → many-keypad-button.tsx} +8 -6
  135. package/src/components/{math-icon.js → math-icon.tsx} +7 -6
  136. package/src/components/{multi-symbol-grid.js → multi-symbol-grid.tsx} +8 -8
  137. package/src/components/{multi-symbol-popover.js → multi-symbol-popover.tsx} +5 -6
  138. package/src/components/{navigation-pad.js → navigation-pad.tsx} +7 -6
  139. package/src/components/{node-manager.js → node-manager.ts} +16 -4
  140. package/src/components/{popover-manager.js → popover-manager.tsx} +13 -16
  141. package/src/components/{popover-state-machine.js → popover-state-machine.ts} +21 -2
  142. package/src/components/prop-types.js +1 -67
  143. package/src/components/provided-keypad.tsx +14 -12
  144. package/src/components/{svg-icon.js → svg-icon.tsx} +5 -6
  145. package/src/components/tabbar/icons.tsx +4 -2
  146. package/src/components/tabbar/item.tsx +1 -3
  147. package/src/components/tabbar/{tabbar.stories.js → tabbar.stories.tsx} +10 -1
  148. package/src/components/tabbar/tabbar.tsx +3 -3
  149. package/src/components/{text-icon.js → text-icon.tsx} +7 -6
  150. package/src/components/{touchable-keypad-button.js → touchable-keypad-button.tsx} +19 -16
  151. package/src/components/{two-page-keypad.js → two-page-keypad.tsx} +13 -9
  152. package/src/components/{velocity-tracker.js → velocity-tracker.ts} +14 -4
  153. package/src/fake-react-native-web/text.tsx +2 -1
  154. package/src/fake-react-native-web/view.tsx +3 -2
  155. package/src/index.ts +1 -4
  156. package/src/store/echo-reducer.ts +58 -0
  157. package/src/store/index.ts +14 -425
  158. package/src/store/input-reducer.ts +55 -0
  159. package/src/store/keypad-reducer.ts +62 -0
  160. package/src/store/layout-reducer.ts +133 -0
  161. package/src/store/pager-reducer.ts +141 -0
  162. package/src/store/shared.ts +12 -0
  163. package/src/store/types.ts +65 -0
  164. package/src/types.ts +69 -0
  165. package/tsconfig.tsbuildinfo +1 -1
  166. package/src/components/app.js +0 -73
  167. package/src/demo.js +0 -9
  168. package/src/native-app.js +0 -85
  169. /package/src/components/__tests__/{node-manager_test.js → node-manager.test.ts} +0 -0
  170. /package/src/components/{compute-layout-parameters.js → compute-layout-parameters.ts} +0 -0
  171. /package/src/components/input/__tests__/{context-tracking_test.js → context-tracking.test.ts} +0 -0
  172. /package/src/components/input/__tests__/{mathquill_test.js → mathquill.test.ts} +0 -0
  173. /package/src/components/input/__tests__/{test-math-wrapper.jsx → test-math-wrapper.ts} +0 -0
  174. /package/src/components/keypad/{button.stories.js → button.stories.tsx} +0 -0
  175. /package/src/components/{styles.js → styles.ts} +0 -0
  176. /package/src/components/tabbar/__tests__/{tabbar_test.js → tabbar.test.tsx} +0 -0
@@ -11,18 +11,6 @@
11
11
 
12
12
  import {toolbarHeightPx} from "../common-style";
13
13
 
14
- // Taken from https://dev.opera.com/articles/fixing-the-scrolltop-bug/
15
- function bodyOrHtml() {
16
- if ("scrollingElement" in document) {
17
- return document.scrollingElement;
18
- }
19
- // Fallback for legacy browsers
20
- if (navigator.userAgent.indexOf("WebKit") !== -1) {
21
- return document.body;
22
- }
23
- return document.documentElement;
24
- }
25
-
26
14
  export const scrollIntoView = (containerNode, keypadNode) => {
27
15
  // TODO(charlie): There's no need for us to be reading the keypad bounds
28
16
  // here, since they're pre-determined by logic in the store. We should
@@ -32,7 +20,7 @@ export const scrollIntoView = (containerNode, keypadNode) => {
32
20
  const containerTopPx = containerBounds.top;
33
21
 
34
22
  // Get the element that scrolls the document.
35
- const scrollNode = bodyOrHtml();
23
+ const scrollNode = document.scrollingElement;
36
24
 
37
25
  const desiredMarginPx = 16;
38
26
 
@@ -58,7 +46,9 @@ export const scrollIntoView = (containerNode, keypadNode) => {
58
46
  containerTopPx,
59
47
  );
60
48
 
61
- scrollNode.scrollTop += scrollOffset;
49
+ if (scrollNode) {
50
+ scrollNode.scrollTop += scrollOffset;
51
+ }
62
52
  return;
63
53
  }
64
54
  }
@@ -66,7 +56,7 @@ export const scrollIntoView = (containerNode, keypadNode) => {
66
56
  // Alternatively, if the input is out of the viewport or nearly out
67
57
  // of the viewport, scroll it into view. We can do this regardless
68
58
  // of whether the keypad has been provided.
69
- if (containerTopPx < desiredMarginPx) {
59
+ if (scrollNode && containerTopPx < desiredMarginPx) {
70
60
  scrollNode.scrollTop -= containerBounds.height + desiredMarginPx;
71
61
  }
72
62
  };
@@ -15,9 +15,9 @@ import * as React from "react";
15
15
  // TODO: This should be an enumeration of all of the possible legal values
16
16
  type KeyId = string;
17
17
 
18
- const buttonAsset: React.FC<{
19
- id: KeyId;
20
- }> = function ({id}): React.ReactElement {
18
+ type Props = {id: KeyId};
19
+
20
+ export default function ButtonAsset({id}: Props): React.ReactElement {
21
21
  switch (id) {
22
22
  case "NUM_0":
23
23
  return (
@@ -489,5 +489,4 @@ const buttonAsset: React.FC<{
489
489
  default:
490
490
  throw new Error(`Invalid asset ${id}`);
491
491
  }
492
- };
493
- export default buttonAsset;
492
+ }
@@ -65,8 +65,7 @@ type Props = {
65
65
  tintColor?: string;
66
66
  };
67
67
 
68
- type State = Record<any, any>;
69
- export default class Button extends React.Component<Props, State> {
68
+ export default class Button extends React.Component<Props> {
70
69
  render(): React.ReactNode {
71
70
  const {onPress, children, style, tintColor} = this.props;
72
71
  return (
@@ -18,7 +18,7 @@ type State = {
18
18
  selectedPage: TabbarItemType;
19
19
  };
20
20
 
21
- const allPages: React.FC<Props> = function (props): React.ReactElement {
21
+ const allPages = function (props: Props): React.ReactElement {
22
22
  const pages: Array<TabbarItemType> = ["Numbers"];
23
23
 
24
24
  if (props.preAlgebra) {
@@ -7,9 +7,13 @@ import ButtonAsset from "./button-assets";
7
7
  import type {KeyConfig} from "../../data/key-configs";
8
8
  import type {StyleType} from "@khanacademy/wonder-blocks-core";
9
9
 
10
- export const KeypadPageContainer: React.FC<{
10
+ type KeypadPageContainerProps = {
11
11
  children: React.ReactNode;
12
- }> = ({children}): React.ReactElement => (
12
+ };
13
+
14
+ export const KeypadPageContainer = ({
15
+ children,
16
+ }: KeypadPageContainerProps): React.ReactElement => (
13
17
  <View
14
18
  style={{
15
19
  backgroundColor: "#DBDCDD",
@@ -25,12 +29,19 @@ export const KeypadPageContainer: React.FC<{
25
29
  </View>
26
30
  );
27
31
 
28
- export const KeypadButton: React.FC<{
32
+ type KeypadButtonProps = {
29
33
  keyConfig: KeyConfig;
30
34
  tintColor?: string;
31
35
  style?: StyleType;
32
36
  onClickKey: (keyConfig: string) => void;
33
- }> = ({keyConfig, onClickKey, tintColor, style}): React.ReactElement => (
37
+ };
38
+
39
+ export const KeypadButton = ({
40
+ keyConfig,
41
+ onClickKey,
42
+ tintColor,
43
+ style,
44
+ }: KeypadButtonProps): React.ReactElement => (
34
45
  <Button
35
46
  onPress={() => onClickKey(keyConfig.id)}
36
47
  tintColor={tintColor}
@@ -40,11 +51,17 @@ export const KeypadButton: React.FC<{
40
51
  </Button>
41
52
  );
42
53
 
43
- export const SecondaryKeypadButton: React.FC<{
54
+ type SecondaryKeypadButtonProps = {
44
55
  keyConfig: KeyConfig;
45
- style?: any;
56
+ style?: StyleType;
46
57
  onClickKey: (keyConfig: string) => void;
47
- }> = ({keyConfig, onClickKey, style}): React.ReactElement => (
58
+ };
59
+
60
+ export const SecondaryKeypadButton = ({
61
+ keyConfig,
62
+ onClickKey,
63
+ style,
64
+ }: SecondaryKeypadButtonProps): React.ReactElement => (
48
65
  <KeypadButton
49
66
  keyConfig={keyConfig}
50
67
  onClickKey={onClickKey}
@@ -53,11 +70,17 @@ export const SecondaryKeypadButton: React.FC<{
53
70
  />
54
71
  );
55
72
 
56
- export const KeypadActionButton: React.FC<{
73
+ type KeypadActionButtonProps = {
57
74
  keyConfig: KeyConfig;
58
- style?: any;
75
+ style?: StyleType;
59
76
  onClickKey: (keyConfig: string) => void;
60
- }> = ({keyConfig, onClickKey, style}): React.ReactElement => (
77
+ };
78
+
79
+ export const KeypadActionButton = ({
80
+ keyConfig,
81
+ onClickKey,
82
+ style,
83
+ }: KeypadActionButtonProps): React.ReactElement => (
61
84
  <KeypadButton
62
85
  keyConfig={keyConfig}
63
86
  onClickKey={onClickKey}
@@ -3,7 +3,6 @@
3
3
  */
4
4
 
5
5
  import {StyleSheet, css} from "aphrodite";
6
- import PropTypes from "prop-types";
7
6
  import * as React from "react";
8
7
  import {connect} from "react-redux";
9
8
 
@@ -23,36 +22,39 @@ import {
23
22
  import CornerDecal from "./corner-decal";
24
23
  import Icon from "./icon";
25
24
  import MultiSymbolGrid from "./multi-symbol-grid";
26
- import {bordersPropType, iconPropType, keyConfigPropType} from "./prop-types";
25
+
26
+ import type {KeyType} from "../consts";
27
+ import type {State} from "../store/types";
28
+ import type {Border, KeyConfig, Icon as IconType} from "../types";
29
+ import type {StyleType} from "@khanacademy/wonder-blocks-core";
30
+
31
+ interface ReduxProps {
32
+ heightPx: number;
33
+ widthPx: number;
34
+ }
35
+
36
+ interface Props extends ReduxProps {
37
+ ariaLabel?: string;
38
+ borders: Border;
39
+ childKeys: ReadonlyArray<KeyConfig>;
40
+ disabled: boolean;
41
+ focused: boolean;
42
+ popoverEnabled: boolean;
43
+ type: KeyType;
44
+ icon: IconType;
45
+ style?: StyleType;
46
+ onTouchCancel?: (evt: React.TouchEvent<HTMLDivElement>) => void;
47
+ onTouchEnd?: (evt: React.TouchEvent<HTMLDivElement>) => void;
48
+ onTouchMove?: (evt: React.TouchEvent<HTMLDivElement>) => void;
49
+ onTouchStart?: (evt: React.TouchEvent<HTMLDivElement>) => void;
50
+ // NOTE(matthewc)[LC-754] this is a normal React thing, but TS
51
+ // gets mad if I don't explicitly set it as a prop
52
+ ref?: (any) => void;
53
+ }
27
54
 
28
55
  // eslint-disable-next-line react/no-unsafe
29
- class KeypadButton extends React.PureComponent {
30
- static propTypes = {
31
- ariaLabel: PropTypes.string,
32
- // The borders to display on the button. Typically, this should be set
33
- // using one of the preset `BorderStyles` options.
34
- borders: bordersPropType,
35
- // Any additional keys that can be accessed by long-pressing on the
36
- // button.
37
- childKeys: PropTypes.arrayOf(keyConfigPropType),
38
- // Whether the button should be rendered in a 'disabled' state, i.e.,
39
- // without any touch feedback.
40
- disabled: PropTypes.bool,
41
- focused: PropTypes.bool,
42
- heightPx: PropTypes.number.isRequired,
43
- icon: iconPropType,
44
- onTouchCancel: PropTypes.func,
45
- onTouchEnd: PropTypes.func,
46
- onTouchMove: PropTypes.func,
47
- onTouchStart: PropTypes.func,
48
- popoverEnabled: PropTypes.bool,
49
- style: PropTypes.any,
50
- type: PropTypes.oneOf(Object.keys(KeyTypes)).isRequired,
51
- // NOTE(charlie): We may want to make this optional for phone layouts
52
- // (and rely on Flexbox instead), since it might not be pixel perfect
53
- // with borders and such.
54
- widthPx: PropTypes.number.isRequired,
55
- };
56
+ class KeypadButton extends React.PureComponent<Props> {
57
+ buttonSizeStyle: StyleType | undefined;
56
58
 
57
59
  static defaultProps = {
58
60
  borders: BorderStyles.ALL,
@@ -126,7 +128,7 @@ class KeypadButton extends React.PureComponent {
126
128
  return [styles.focusBox, focusBackgroundStyle];
127
129
  };
128
130
 
129
- _getButtonStyle = (type, borders, style) => {
131
+ _getButtonStyle = (type, borders, style?) => {
130
132
  // Select the appropriate style for the button.
131
133
  let backgroundStyle;
132
134
  switch (type) {
@@ -154,10 +156,12 @@ class KeypadButton extends React.PureComponent {
154
156
  }
155
157
 
156
158
  const borderStyle = [];
157
- if (borders.indexOf(BorderDirections.LEFT) !== -1) {
159
+ if (borders.includes(BorderDirections.LEFT)) {
160
+ // @ts-expect-error TS2345
158
161
  borderStyle.push(styles.leftBorder);
159
162
  }
160
- if (borders.indexOf(BorderDirections.BOTTOM) !== -1) {
163
+ if (borders.includes(BorderDirections.BOTTOM)) {
164
+ // @ts-expect-error TS2345
161
165
  borderStyle.push(styles.bottomBorder);
162
166
  }
163
167
 
@@ -199,7 +203,7 @@ class KeypadButton extends React.PureComponent {
199
203
  const focusStyle = this._getFocusStyle(type);
200
204
  const iconWrapperStyle = [
201
205
  styles.iconWrapper,
202
- disabled && styles.disabled,
206
+ disabled ? styles.disabled : undefined,
203
207
  ];
204
208
 
205
209
  const eventHandlers = {
@@ -267,8 +271,6 @@ const focusBoxZIndex = 0;
267
271
 
268
272
  const styles = StyleSheet.create({
269
273
  buttonBase: {
270
- // HACK(benkomalo): support old style flex box in Android browsers
271
- "-webkit-box-flex": "1",
272
274
  flex: 1,
273
275
  cursor: "pointer",
274
276
  // Make the text unselectable
@@ -353,8 +355,11 @@ const styleForButtonDimensions = (heightPx, widthPx) => {
353
355
  }).buttonSize;
354
356
  };
355
357
 
356
- const mapStateToProps = (state) => {
357
- return state.layout.buttonDimensions;
358
+ const mapStateToProps = (state: State): ReduxProps => {
359
+ return {
360
+ heightPx: state.layout.buttonDimensions.heightPx,
361
+ widthPx: state.layout.buttonDimensions.widthPx,
362
+ };
358
363
  };
359
364
 
360
365
  export default connect(mapStateToProps, null, null, {forwardRef: true})(
@@ -1,5 +1,4 @@
1
1
  import {StyleSheet} from "aphrodite";
2
- import PropTypes from "prop-types";
3
2
  import * as React from "react";
4
3
  import {connect} from "react-redux";
5
4
 
@@ -16,27 +15,39 @@ import {
16
15
  import ExpressionKeypad from "./expression-keypad";
17
16
  import FractionKeypad from "./fraction-keypad";
18
17
  import NavigationPad from "./navigation-pad";
19
- import {keyIdPropType} from "./prop-types";
20
18
  import Styles from "./styles";
21
19
  import * as zIndexes from "./z-indexes";
22
20
 
21
+ import type {KeypadType} from "../consts";
22
+ import type {State as ReduxState} from "../store/types";
23
+ import type {StyleType} from "@khanacademy/wonder-blocks-core";
24
+
23
25
  const {row, centered, fullWidth} = Styles;
24
26
 
27
+ interface ReduxProps {
28
+ active?: boolean;
29
+ extraKeys?: ReadonlyArray<string>;
30
+ keypadType?: KeypadType;
31
+ layoutMode?: keyof typeof LayoutModes;
32
+ navigationPadEnabled?: boolean;
33
+ }
34
+
35
+ interface Props extends ReduxProps {
36
+ onDismiss?: () => void;
37
+ onElementMounted: (element: any) => void;
38
+ onPageSizeChange?: (width: number, height: number) => void;
39
+ style?: StyleType;
40
+ }
41
+
42
+ type State = {
43
+ hasBeenActivated: boolean;
44
+ viewportWidth: string | number;
45
+ };
46
+
25
47
  // eslint-disable-next-line react/no-unsafe
26
- class KeypadContainer extends React.Component {
27
- static propTypes = {
28
- active: PropTypes.bool,
29
- extraKeys: PropTypes.arrayOf(keyIdPropType),
30
- keypadType: PropTypes.oneOf(Object.keys(KeypadTypes)).isRequired,
31
- layoutMode: PropTypes.oneOf(Object.keys(LayoutModes)).isRequired,
32
- navigationPadEnabled: PropTypes.bool.isRequired,
33
- onDismiss: PropTypes.func,
34
- // A callback that should be triggered with the root React element on
35
- // mount.
36
- onElementMounted: PropTypes.func,
37
- onPageSizeChange: PropTypes.func.isRequired,
38
- style: PropTypes.any,
39
- };
48
+ class KeypadContainer extends React.Component<Props, State> {
49
+ _resizeTimeout: number | null | undefined;
50
+ hasMounted: boolean | undefined;
40
51
 
41
52
  state = {
42
53
  hasBeenActivated: false,
@@ -89,7 +100,7 @@ class KeypadContainer extends React.Component {
89
100
  // Throttle the resize callbacks.
90
101
  // https://developer.mozilla.org/en-US/docs/Web/Events/resize
91
102
  if (this._resizeTimeout == null) {
92
- this._resizeTimeout = setTimeout(() => {
103
+ this._resizeTimeout = window.setTimeout(() => {
93
104
  this._resizeTimeout = null;
94
105
 
95
106
  this._onResize();
@@ -103,8 +114,7 @@ class KeypadContainer extends React.Component {
103
114
  this.setState({
104
115
  viewportWidth: window.innerWidth,
105
116
  });
106
-
107
- this.props.onPageSizeChange(window.innerWidth, window.innerHeight);
117
+ this.props.onPageSizeChange?.(window.innerWidth, window.innerHeight);
108
118
  };
109
119
 
110
120
  renderKeypad = () => {
@@ -154,11 +164,17 @@ class KeypadContainer extends React.Component {
154
164
  // NOTE(charlie): We render the transforms as pure inline styles to
155
165
  // avoid an Aphrodite bug in mobile Safari.
156
166
  // See: https://github.com/Khan/aphrodite/issues/68.
157
- const dynamicStyle = {
167
+ let dynamicStyle = {
158
168
  ...(active ? inlineStyles.active : inlineStyles.hidden),
159
- ...(!active && !hasBeenActivated ? inlineStyles.invisible : {}),
160
169
  };
161
170
 
171
+ if (!active && !hasBeenActivated) {
172
+ dynamicStyle = {
173
+ ...dynamicStyle,
174
+ ...inlineStyles.invisible,
175
+ };
176
+ }
177
+
162
178
  const keypadContainerStyle = [
163
179
  row,
164
180
  centered,
@@ -278,9 +294,11 @@ const inlineStyles = {
278
294
  },
279
295
  };
280
296
 
281
- const mapStateToProps = (state) => {
297
+ const mapStateToProps = (state: ReduxState): ReduxProps => {
282
298
  return {
283
- ...state.keypad,
299
+ extraKeys: state.keypad.extraKeys,
300
+ keypadType: state.keypad.keypadType,
301
+ active: state.keypad.active,
284
302
  layoutMode: state.layout.layoutMode,
285
303
  navigationPadEnabled: state.layout.navigationPadEnabled,
286
304
  };
@@ -3,7 +3,6 @@
3
3
  * and manages the rendering of echo animations on top of those buttons.
4
4
  */
5
5
 
6
- import PropTypes from "prop-types";
7
6
  import * as React from "react";
8
7
  import ReactDOM from "react-dom";
9
8
  import {connect} from "react-redux";
@@ -13,26 +12,28 @@ import {View} from "../fake-react-native-web/index";
13
12
 
14
13
  import EchoManager from "./echo-manager";
15
14
  import PopoverManager from "./popover-manager";
16
- import {echoPropType, popoverPropType} from "./prop-types";
15
+
16
+ import type {State} from "../store/types";
17
+ import type {Popover, Echo} from "../types";
18
+ import type {StyleType} from "@khanacademy/wonder-blocks-core";
19
+
20
+ interface ReduxProps {
21
+ active: boolean;
22
+ echoes: ReadonlyArray<Echo>;
23
+ popover: Popover | null;
24
+ }
25
+
26
+ interface Props extends ReduxProps {
27
+ children: React.ReactNode;
28
+ style?: StyleType;
29
+ removeEcho?: (animationId: string) => void;
30
+ }
17
31
 
18
32
  // eslint-disable-next-line react/no-unsafe
19
- class Keypad extends React.Component {
20
- static propTypes = {
21
- children: PropTypes.oneOfType([
22
- PropTypes.arrayOf(PropTypes.node),
23
- PropTypes.node,
24
- ]),
25
- removeEcho: PropTypes.func.isRequired,
26
- style: PropTypes.any,
27
-
28
- // The props below are injected by redux
29
-
30
- // Whether the keypad is active, i.e., whether it should be rendered as
31
- // visible or invisible.
32
- active: PropTypes.bool,
33
- echoes: PropTypes.arrayOf(echoPropType).isRequired,
34
- popover: popoverPropType,
35
- };
33
+ class Keypad extends React.Component<Props> {
34
+ _isMounted: boolean | undefined;
35
+ _resizeTimeout: number | null | undefined;
36
+ _container: DOMRect | null | undefined;
36
37
 
37
38
  componentDidMount() {
38
39
  this._isMounted = true;
@@ -54,7 +55,7 @@ class Keypad extends React.Component {
54
55
  }
55
56
 
56
57
  _computeContainer = () => {
57
- const domNode = ReactDOM.findDOMNode(this);
58
+ const domNode = ReactDOM.findDOMNode(this) as Element;
58
59
  this._container = domNode.getBoundingClientRect();
59
60
  };
60
61
 
@@ -76,7 +77,7 @@ class Keypad extends React.Component {
76
77
  // Throttle resize events -- taken from:
77
78
  // https://developer.mozilla.org/en-US/docs/Web/Events/resize
78
79
  if (this._resizeTimeout == null) {
79
- this._resizeTimeout = setTimeout(() => {
80
+ this._resizeTimeout = window.setTimeout(() => {
80
81
  this._resizeTimeout = null;
81
82
 
82
83
  if (this._isMounted) {
@@ -96,9 +97,13 @@ class Keypad extends React.Component {
96
97
  return {
97
98
  ...rest,
98
99
  initialBounds: {
100
+ // @ts-expect-error TS2533
99
101
  top: initialBounds.top - this._container.top,
102
+ // @ts-expect-error TS2533
100
103
  right: initialBounds.right - this._container.left,
104
+ // @ts-expect-error TS2533
101
105
  bottom: initialBounds.bottom - this._container.top,
106
+ // @ts-expect-error TS2533
102
107
  left: initialBounds.left - this._container.left,
103
108
  width: initialBounds.width,
104
109
  height: initialBounds.height,
@@ -113,8 +118,11 @@ class Keypad extends React.Component {
113
118
  ...popover,
114
119
  bounds: {
115
120
  bottom:
121
+ // @ts-expect-error TS2533
116
122
  this._container.height -
123
+ // @ts-expect-error TS2533
117
124
  (popover.bounds.bottom - this._container.top),
125
+ // @ts-expect-error TS2533
118
126
  left: popover.bounds.left - this._container.left,
119
127
  width: popover.bounds.width,
120
128
  },
@@ -133,9 +141,9 @@ class Keypad extends React.Component {
133
141
  }
134
142
  }
135
143
 
136
- const mapStateToProps = (state) => {
144
+ const mapStateToProps = (state: State): ReduxProps => {
137
145
  return {
138
- ...state.echoes,
146
+ echoes: state.echoes.echoes,
139
147
  active: state.keypad.active,
140
148
  popover: state.gestures.popover,
141
149
  };
@@ -3,7 +3,6 @@
3
3
  * 'default' symbol.
4
4
  */
5
5
 
6
- import PropTypes from "prop-types";
7
6
  import * as React from "react";
8
7
 
9
8
  import {KeyTypes} from "../consts";
@@ -11,12 +10,15 @@ import KeyConfigs from "../data/key-configs";
11
10
  import Keys from "../data/keys";
12
11
 
13
12
  import EmptyKeypadButton from "./empty-keypad-button";
14
- import {keyIdPropType} from "./prop-types";
15
13
  import TouchableKeypadButton from "./touchable-keypad-button";
16
14
 
17
- class ManyKeypadButton extends React.Component {
18
- static propTypes = {
19
- keys: PropTypes.arrayOf(keyIdPropType).isRequired,
15
+ type Props = {
16
+ keys: ReadonlyArray<string>;
17
+ };
18
+
19
+ class ManyKeypadButton extends React.Component<Props> {
20
+ static defaultProps = {
21
+ keys: [],
20
22
  };
21
23
 
22
24
  render() {
@@ -26,7 +28,7 @@ class ManyKeypadButton extends React.Component {
26
28
  // one, render a standard button. Otherwise, capture them all in a
27
29
  // single button.
28
30
  if (keys.length === 0) {
29
- return <EmptyKeypadButton {...rest} />;
31
+ return <EmptyKeypadButton />;
30
32
  } else if (keys.length === 1) {
31
33
  const keyConfig = KeyConfigs[keys[0]];
32
34
  return <TouchableKeypadButton keyConfig={keyConfig} {...rest} />;
@@ -4,7 +4,6 @@
4
4
 
5
5
  import {StyleSheet} from "aphrodite";
6
6
  import katex from "katex";
7
- import PropTypes from "prop-types";
8
7
  import * as React from "react";
9
8
  import ReactDOM from "react-dom";
10
9
 
@@ -13,14 +12,16 @@ import {View} from "../fake-react-native-web/index";
13
12
  import {iconSizeHeightPx, iconSizeWidthPx} from "./common-style";
14
13
  import Styles from "./styles";
15
14
 
15
+ import type {StyleType} from "@khanacademy/wonder-blocks-core";
16
+
16
17
  const {row, centered} = Styles;
17
18
 
18
- class MathIcon extends React.Component {
19
- static propTypes = {
20
- math: PropTypes.string.isRequired,
21
- style: PropTypes.any,
22
- };
19
+ type Props = {
20
+ math: string;
21
+ style: StyleType;
22
+ };
23
23
 
24
+ class MathIcon extends React.Component<Props> {
24
25
  componentDidMount() {
25
26
  this._renderMath();
26
27
  }
@@ -4,7 +4,6 @@
4
4
  */
5
5
 
6
6
  import {StyleSheet} from "aphrodite";
7
- import PropTypes from "prop-types";
8
7
  import * as React from "react";
9
8
 
10
9
  import {IconTypes} from "../consts";
@@ -12,17 +11,18 @@ import {View} from "../fake-react-native-web/index";
12
11
 
13
12
  import {iconSizeHeightPx, iconSizeWidthPx} from "./common-style";
14
13
  import Icon from "./icon";
15
- import {iconPropType} from "./prop-types";
16
14
  import Styles from "./styles";
17
15
 
16
+ import type {Icon as IconType} from "../types";
17
+
18
18
  const {row, column, centered, fullWidth} = Styles;
19
19
 
20
- class MultiSymbolGrid extends React.Component {
21
- static propTypes = {
22
- focused: PropTypes.bool,
23
- icons: PropTypes.arrayOf(iconPropType).isRequired,
24
- };
20
+ type Props = {
21
+ focused: boolean;
22
+ icons: ReadonlyArray<IconType>;
23
+ };
25
24
 
25
+ class MultiSymbolGrid extends React.Component<Props> {
26
26
  render() {
27
27
  const {focused, icons} = this.props;
28
28
 
@@ -131,7 +131,7 @@ class MultiSymbolGrid extends React.Component {
131
131
  }
132
132
  }
133
133
 
134
- throw new Error("Invalid number of icons:", icons.length);
134
+ throw new Error(`Invalid number of icons: ${icons.length}`);
135
135
  }
136
136
  }
137
137
 
@@ -3,21 +3,20 @@
3
3
  */
4
4
 
5
5
  import {StyleSheet} from "aphrodite";
6
- import PropTypes from "prop-types";
7
6
  import * as React from "react";
8
7
 
9
8
  import {BorderStyles} from "../consts";
10
9
  import {View} from "../fake-react-native-web/index";
10
+ import {KeyConfig} from "../types";
11
11
 
12
- import {keyConfigPropType} from "./prop-types";
13
12
  import TouchableKeypadButton from "./touchable-keypad-button";
14
13
  import * as zIndexes from "./z-indexes";
15
14
 
16
- class MultiSymbolPopover extends React.Component {
17
- static propTypes = {
18
- keys: PropTypes.arrayOf(keyConfigPropType),
19
- };
15
+ type Prop = {
16
+ keys: ReadonlyArray<KeyConfig>;
17
+ };
20
18
 
19
+ class MultiSymbolPopover extends React.Component<Prop> {
21
20
  render() {
22
21
  const {keys} = this.props;
23
22