@khanacademy/math-input 15.0.1 → 16.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 (140) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/components/aphrodite-css-transition-group/transition-child.d.ts +11 -8
  3. package/dist/components/keypad/index.d.ts +1 -1
  4. package/dist/components/keypad/mobile-keypad-internals.d.ts +49 -0
  5. package/dist/components/keypad/mobile-keypad.d.ts +4 -48
  6. package/dist/es/index.js +168 -4740
  7. package/dist/es/index.js.map +1 -1
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.js +166 -4722
  10. package/dist/index.js.map +1 -1
  11. package/package.json +10 -9
  12. package/src/components/__tests__/integration.test.tsx +2 -3
  13. package/src/components/keypad/__tests__/mobile-keypad.test.tsx +8 -8
  14. package/src/components/keypad/index.tsx +1 -1
  15. package/src/components/keypad/mobile-keypad-internals.tsx +240 -0
  16. package/src/components/keypad/mobile-keypad.tsx +21 -234
  17. package/src/full-mobile-input.stories.tsx +0 -1
  18. package/src/index.ts +1 -1
  19. package/tsconfig-build.tsbuildinfo +1 -1
  20. package/dist/components/keypad-legacy/compute-layout-parameters.d.ts +0 -28
  21. package/dist/components/keypad-legacy/corner-decal.d.ts +0 -12
  22. package/dist/components/keypad-legacy/echo-manager.d.ts +0 -17
  23. package/dist/components/keypad-legacy/empty-keypad-button.d.ts +0 -13
  24. package/dist/components/keypad-legacy/expression-keypad.d.ts +0 -21
  25. package/dist/components/keypad-legacy/fraction-keypad.d.ts +0 -21
  26. package/dist/components/keypad-legacy/gesture-manager.d.ts +0 -86
  27. package/dist/components/keypad-legacy/gesture-state-machine.d.ts +0 -105
  28. package/dist/components/keypad-legacy/icon.d.ts +0 -15
  29. package/dist/components/keypad-legacy/index.d.ts +0 -1
  30. package/dist/components/keypad-legacy/keypad-button.d.ts +0 -53
  31. package/dist/components/keypad-legacy/keypad-container.d.ts +0 -41
  32. package/dist/components/keypad-legacy/keypad.d.ts +0 -31
  33. package/dist/components/keypad-legacy/many-keypad-button.d.ts +0 -15
  34. package/dist/components/keypad-legacy/math-icon.d.ts +0 -16
  35. package/dist/components/keypad-legacy/multi-symbol-grid.d.ts +0 -14
  36. package/dist/components/keypad-legacy/multi-symbol-popover.d.ts +0 -12
  37. package/dist/components/keypad-legacy/navigation-pad.d.ts +0 -14
  38. package/dist/components/keypad-legacy/node-manager.d.ts +0 -49
  39. package/dist/components/keypad-legacy/popover-manager.d.ts +0 -13
  40. package/dist/components/keypad-legacy/popover-state-machine.d.ts +0 -68
  41. package/dist/components/keypad-legacy/provided-keypad.d.ts +0 -28
  42. package/dist/components/keypad-legacy/store/actions.d.ts +0 -55
  43. package/dist/components/keypad-legacy/store/echo-reducer.d.ts +0 -4
  44. package/dist/components/keypad-legacy/store/index.d.ts +0 -9
  45. package/dist/components/keypad-legacy/store/input-reducer.d.ts +0 -4
  46. package/dist/components/keypad-legacy/store/keypad-reducer.d.ts +0 -4
  47. package/dist/components/keypad-legacy/store/layout-reducer.d.ts +0 -4
  48. package/dist/components/keypad-legacy/store/shared.d.ts +0 -7
  49. package/dist/components/keypad-legacy/store/types.d.ts +0 -47
  50. package/dist/components/keypad-legacy/styles.d.ts +0 -5
  51. package/dist/components/keypad-legacy/svg-icon.d.ts +0 -12
  52. package/dist/components/keypad-legacy/text-icon.d.ts +0 -13
  53. package/dist/components/keypad-legacy/touchable-keypad-button.d.ts +0 -37
  54. package/dist/components/keypad-legacy/two-page-keypad.d.ts +0 -21
  55. package/dist/components/keypad-legacy/z-indexes.d.ts +0 -7
  56. package/dist/components/keypad-switch.d.ts +0 -12
  57. package/src/components/keypad-legacy/__tests__/gesture-state-machine.test.ts +0 -441
  58. package/src/components/keypad-legacy/__tests__/node-manager.test.ts +0 -89
  59. package/src/components/keypad-legacy/__tests__/two-page-keypad.test.tsx +0 -38
  60. package/src/components/keypad-legacy/compute-layout-parameters.ts +0 -205
  61. package/src/components/keypad-legacy/corner-decal.tsx +0 -56
  62. package/src/components/keypad-legacy/echo-manager.tsx +0 -152
  63. package/src/components/keypad-legacy/empty-keypad-button.tsx +0 -58
  64. package/src/components/keypad-legacy/expression-keypad.tsx +0 -315
  65. package/src/components/keypad-legacy/fraction-keypad.tsx +0 -180
  66. package/src/components/keypad-legacy/gesture-manager.ts +0 -255
  67. package/src/components/keypad-legacy/gesture-state-machine.ts +0 -329
  68. package/src/components/keypad-legacy/icon.tsx +0 -72
  69. package/src/components/keypad-legacy/iconography/arrow.js +0 -22
  70. package/src/components/keypad-legacy/iconography/backspace.js +0 -29
  71. package/src/components/keypad-legacy/iconography/cdot.js +0 -29
  72. package/src/components/keypad-legacy/iconography/cos.js +0 -30
  73. package/src/components/keypad-legacy/iconography/cube-root.js +0 -36
  74. package/src/components/keypad-legacy/iconography/dismiss.js +0 -25
  75. package/src/components/keypad-legacy/iconography/divide.js +0 -34
  76. package/src/components/keypad-legacy/iconography/down.js +0 -16
  77. package/src/components/keypad-legacy/iconography/equal.js +0 -33
  78. package/src/components/keypad-legacy/iconography/exp-2.js +0 -29
  79. package/src/components/keypad-legacy/iconography/exp-3.js +0 -29
  80. package/src/components/keypad-legacy/iconography/exp.js +0 -29
  81. package/src/components/keypad-legacy/iconography/frac.js +0 -44
  82. package/src/components/keypad-legacy/iconography/geq.js +0 -33
  83. package/src/components/keypad-legacy/iconography/gt.js +0 -33
  84. package/src/components/keypad-legacy/iconography/index.js +0 -45
  85. package/src/components/keypad-legacy/iconography/jump-into-numerator.js +0 -41
  86. package/src/components/keypad-legacy/iconography/jump-out-base.js +0 -30
  87. package/src/components/keypad-legacy/iconography/jump-out-denominator.js +0 -41
  88. package/src/components/keypad-legacy/iconography/jump-out-exponent.js +0 -30
  89. package/src/components/keypad-legacy/iconography/jump-out-numerator.js +0 -41
  90. package/src/components/keypad-legacy/iconography/jump-out-parentheses.js +0 -33
  91. package/src/components/keypad-legacy/iconography/left-paren.js +0 -33
  92. package/src/components/keypad-legacy/iconography/left.js +0 -16
  93. package/src/components/keypad-legacy/iconography/leq.js +0 -33
  94. package/src/components/keypad-legacy/iconography/ln.js +0 -29
  95. package/src/components/keypad-legacy/iconography/log-n.js +0 -29
  96. package/src/components/keypad-legacy/iconography/log.js +0 -29
  97. package/src/components/keypad-legacy/iconography/lt.js +0 -33
  98. package/src/components/keypad-legacy/iconography/minus.js +0 -32
  99. package/src/components/keypad-legacy/iconography/neq.js +0 -33
  100. package/src/components/keypad-legacy/iconography/parens.js +0 -33
  101. package/src/components/keypad-legacy/iconography/percent.js +0 -49
  102. package/src/components/keypad-legacy/iconography/period.js +0 -26
  103. package/src/components/keypad-legacy/iconography/plus.js +0 -32
  104. package/src/components/keypad-legacy/iconography/radical.js +0 -36
  105. package/src/components/keypad-legacy/iconography/right-paren.js +0 -33
  106. package/src/components/keypad-legacy/iconography/right.js +0 -16
  107. package/src/components/keypad-legacy/iconography/sin.js +0 -30
  108. package/src/components/keypad-legacy/iconography/sqrt.js +0 -32
  109. package/src/components/keypad-legacy/iconography/tan.js +0 -30
  110. package/src/components/keypad-legacy/iconography/times.js +0 -33
  111. package/src/components/keypad-legacy/iconography/up.js +0 -16
  112. package/src/components/keypad-legacy/index.ts +0 -1
  113. package/src/components/keypad-legacy/keypad-button.tsx +0 -368
  114. package/src/components/keypad-legacy/keypad-container.tsx +0 -358
  115. package/src/components/keypad-legacy/keypad.tsx +0 -162
  116. package/src/components/keypad-legacy/many-keypad-button.tsx +0 -54
  117. package/src/components/keypad-legacy/math-icon.tsx +0 -66
  118. package/src/components/keypad-legacy/multi-symbol-grid.tsx +0 -182
  119. package/src/components/keypad-legacy/multi-symbol-popover.tsx +0 -58
  120. package/src/components/keypad-legacy/navigation-pad.tsx +0 -140
  121. package/src/components/keypad-legacy/node-manager.ts +0 -133
  122. package/src/components/keypad-legacy/popover-manager.tsx +0 -73
  123. package/src/components/keypad-legacy/popover-state-machine.ts +0 -184
  124. package/src/components/keypad-legacy/provided-keypad.tsx +0 -136
  125. package/src/components/keypad-legacy/store/actions.ts +0 -155
  126. package/src/components/keypad-legacy/store/echo-reducer.ts +0 -57
  127. package/src/components/keypad-legacy/store/index.ts +0 -110
  128. package/src/components/keypad-legacy/store/input-reducer.ts +0 -55
  129. package/src/components/keypad-legacy/store/keypad-reducer.ts +0 -58
  130. package/src/components/keypad-legacy/store/layout-reducer.test.ts +0 -171
  131. package/src/components/keypad-legacy/store/layout-reducer.ts +0 -129
  132. package/src/components/keypad-legacy/store/shared.ts +0 -12
  133. package/src/components/keypad-legacy/store/types.ts +0 -78
  134. package/src/components/keypad-legacy/styles.ts +0 -38
  135. package/src/components/keypad-legacy/svg-icon.tsx +0 -24
  136. package/src/components/keypad-legacy/text-icon.tsx +0 -53
  137. package/src/components/keypad-legacy/touchable-keypad-button.tsx +0 -163
  138. package/src/components/keypad-legacy/two-page-keypad.tsx +0 -115
  139. package/src/components/keypad-legacy/z-indexes.ts +0 -8
  140. package/src/components/keypad-switch.tsx +0 -42
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": "15.0.1",
6
+ "version": "16.0.0",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },
@@ -25,18 +25,18 @@
25
25
  "performance-now": "^0.2.0"
26
26
  },
27
27
  "devDependencies": {
28
- "@khanacademy/wonder-blocks-clickable": "^4.0.0",
29
- "@khanacademy/wonder-blocks-color": "^2.0.1",
30
- "@khanacademy/wonder-blocks-core": "^6.0.0",
28
+ "@khanacademy/wonder-blocks-clickable": "^4.0.11",
29
+ "@khanacademy/wonder-blocks-color": "^3.0.0",
30
+ "@khanacademy/wonder-blocks-core": "^6.3.0",
31
31
  "@khanacademy/wonder-blocks-i18n": "^2.0.2",
32
- "@khanacademy/wonder-blocks-popover": "^2.0.11",
32
+ "@khanacademy/wonder-blocks-popover": "^3.0.16",
33
33
  "@khanacademy/wonder-blocks-timing": "^4.0.2",
34
34
  "@khanacademy/wonder-stuff-core": "^1.5.1",
35
35
  "@phosphor-icons/core": "^2.0.2",
36
36
  "aphrodite": "^1.1.0",
37
37
  "jquery": "^2.1.1",
38
38
  "katex": "^0.11.1",
39
- "perseus-build-settings": "^0.2.1",
39
+ "perseus-build-settings": "^0.3.0",
40
40
  "prop-types": "15.6.1",
41
41
  "react": "^16.8.0",
42
42
  "react-dom": "^16.8.0",
@@ -47,10 +47,11 @@
47
47
  "redux": "^4.0.0"
48
48
  },
49
49
  "peerDependencies": {
50
- "@khanacademy/wonder-blocks-clickable": "^4.0.0",
51
- "@khanacademy/wonder-blocks-color": "^2.0.1",
52
- "@khanacademy/wonder-blocks-core": "^6.0.0",
50
+ "@khanacademy/wonder-blocks-clickable": "^4.0.11",
51
+ "@khanacademy/wonder-blocks-color": "^3.0.0",
52
+ "@khanacademy/wonder-blocks-core": "^6.3.0",
53
53
  "@khanacademy/wonder-blocks-i18n": "^2.0.2",
54
+ "@khanacademy/wonder-blocks-popover": "^3.0.16",
54
55
  "@khanacademy/wonder-blocks-timing": "^4.0.2",
55
56
  "@khanacademy/wonder-stuff-core": "^1.5.1",
56
57
  "@phosphor-icons/core": "^2.0.2",
@@ -12,8 +12,8 @@ import React, {useState} from "react";
12
12
 
13
13
  import {KeypadType} from "../../enums";
14
14
  import MathInput from "../input/math-input";
15
+ import {MobileKeypad} from "../keypad";
15
16
  import {KeypadContext, StatefulKeypadContextProvider} from "../keypad-context";
16
- import KeypadSwitch from "../keypad-switch";
17
17
 
18
18
  import type {KeypadConfiguration} from "../../types";
19
19
 
@@ -60,11 +60,10 @@ function KeypadWithContext() {
60
60
  <KeypadContext.Consumer>
61
61
  {({setKeypadElement}) => {
62
62
  return (
63
- <KeypadSwitch
63
+ <MobileKeypad
64
64
  onElementMounted={setKeypadElement}
65
65
  onDismiss={() => {}}
66
66
  onAnalyticsEvent={async () => {}}
67
- useV2Keypad
68
67
  />
69
68
  );
70
69
  }}
@@ -2,14 +2,14 @@ import {render, screen} from "@testing-library/react";
2
2
  import * as React from "react";
3
3
  import "@testing-library/jest-dom";
4
4
 
5
- import MobileKeypad from "../mobile-keypad";
5
+ import MobileKeypadInternals from "../mobile-keypad-internals";
6
6
 
7
7
  describe("mobile keypad", () => {
8
8
  it("should render keypad when active", () => {
9
9
  // Arrange
10
10
  // Act
11
11
  const {container} = render(
12
- <MobileKeypad
12
+ <MobileKeypadInternals
13
13
  onAnalyticsEvent={async () => undefined}
14
14
  setKeypadActive={(keypadActive: boolean) => undefined}
15
15
  keypadActive={true}
@@ -24,7 +24,7 @@ describe("mobile keypad", () => {
24
24
  // Arrange
25
25
  // Act
26
26
  const {container} = render(
27
- <MobileKeypad
27
+ <MobileKeypadInternals
28
28
  onAnalyticsEvent={async () => undefined}
29
29
  setKeypadActive={(keypadActive: boolean) => undefined}
30
30
  keypadActive={false}
@@ -38,7 +38,7 @@ describe("mobile keypad", () => {
38
38
  it("should render the keypad when going from keypadActive=false to keypadActive=true", () => {
39
39
  // Arrange
40
40
  const {rerender} = render(
41
- <MobileKeypad
41
+ <MobileKeypadInternals
42
42
  onAnalyticsEvent={async () => undefined}
43
43
  setKeypadActive={(keypadActive: boolean) => undefined}
44
44
  keypadActive={false}
@@ -49,7 +49,7 @@ describe("mobile keypad", () => {
49
49
 
50
50
  // Act
51
51
  rerender(
52
- <MobileKeypad
52
+ <MobileKeypadInternals
53
53
  onAnalyticsEvent={async () => undefined}
54
54
  setKeypadActive={(keypadActive: boolean) => undefined}
55
55
  keypadActive={true}
@@ -66,7 +66,7 @@ describe("mobile keypad", () => {
66
66
 
67
67
  // Act
68
68
  render(
69
- <MobileKeypad
69
+ <MobileKeypadInternals
70
70
  onAnalyticsEvent={onAnalyticsEvent}
71
71
  setKeypadActive={(keypadActive: boolean) => undefined}
72
72
  keypadActive={true}
@@ -87,7 +87,7 @@ describe("mobile keypad", () => {
87
87
 
88
88
  // Arrange
89
89
  const {rerender, unmount} = render(
90
- <MobileKeypad
90
+ <MobileKeypadInternals
91
91
  onAnalyticsEvent={onAnalyticsEvent}
92
92
  setKeypadActive={(keypadActive: boolean) => undefined}
93
93
  keypadActive={true}
@@ -96,7 +96,7 @@ describe("mobile keypad", () => {
96
96
 
97
97
  // Act
98
98
  rerender(
99
- <MobileKeypad
99
+ <MobileKeypadInternals
100
100
  onAnalyticsEvent={onAnalyticsEvent}
101
101
  setKeypadActive={(keypadActive: boolean) => undefined}
102
102
  keypadActive={false}
@@ -1,2 +1,2 @@
1
1
  export {default} from "./keypad";
2
- export {default as MobileKeypad} from "./mobile-keypad";
2
+ export {MobileKeypad} from "./mobile-keypad";
@@ -0,0 +1,240 @@
1
+ import {StyleSheet} from "aphrodite";
2
+ import * as React from "react";
3
+ import ReactDOM from "react-dom";
4
+
5
+ import {View} from "../../fake-react-native-web/index";
6
+ import AphroditeCssTransitionGroup from "../aphrodite-css-transition-group";
7
+
8
+ import Keypad from "./keypad";
9
+ import {expandedViewThreshold} from "./utils";
10
+
11
+ import type Key from "../../data/keys";
12
+ import type {
13
+ Cursor,
14
+ KeypadConfiguration,
15
+ KeyHandler,
16
+ KeypadAPI,
17
+ } from "../../types";
18
+ import type {AnalyticsEventHandlerFn} from "@khanacademy/perseus-core";
19
+ import type {StyleType} from "@khanacademy/wonder-blocks-core";
20
+
21
+ const AnimationDurationInMS = 200;
22
+
23
+ type Props = {
24
+ onElementMounted?: (arg1: any) => void;
25
+ onDismiss?: () => void;
26
+ style?: StyleType;
27
+ onAnalyticsEvent: AnalyticsEventHandlerFn;
28
+ setKeypadActive: (keypadActive: boolean) => void;
29
+ keypadActive: boolean;
30
+ };
31
+
32
+ type State = {
33
+ containerWidth: number;
34
+ keypadConfig?: KeypadConfiguration;
35
+ keyHandler?: KeyHandler;
36
+ cursor?: Cursor;
37
+ };
38
+
39
+ /**
40
+ * This is the v2 equivalent of v1's ProvidedKeypad. It follows the same
41
+ * external API so that it can be hot-swapped with the v1 keypad and
42
+ * is responsible for connecting the keypad with MathInput and the Renderer.
43
+ *
44
+ * Ideally this strategy of attaching methods on the class component for
45
+ * other components to call will be replaced props/callbacks since React
46
+ * doesn't support this type of code anymore (functional components
47
+ * can't have methods attached to them).
48
+ */
49
+ class MobileKeypadInternals
50
+ extends React.Component<Props, State>
51
+ implements KeypadAPI
52
+ {
53
+ _containerRef = React.createRef<HTMLDivElement>();
54
+ _containerResizeObserver: ResizeObserver | null = null;
55
+ _throttleResize = false;
56
+
57
+ state: State = {
58
+ containerWidth: 0,
59
+ };
60
+
61
+ componentDidMount() {
62
+ this._resize();
63
+
64
+ window.addEventListener("resize", this._throttleResizeHandler);
65
+ window.addEventListener(
66
+ "orientationchange",
67
+ this._throttleResizeHandler,
68
+ );
69
+
70
+ // LC-1213: some common older browsers (as of 2023-09-07)
71
+ // don't support ResizeObserver
72
+ if ("ResizeObserver" in window) {
73
+ this._containerResizeObserver = new window.ResizeObserver(
74
+ this._throttleResizeHandler,
75
+ );
76
+
77
+ if (this._containerRef.current) {
78
+ this._containerResizeObserver.observe(
79
+ this._containerRef.current,
80
+ );
81
+ }
82
+ }
83
+
84
+ this.props.onElementMounted?.({
85
+ activate: this.activate,
86
+ dismiss: this.dismiss,
87
+ configure: this.configure,
88
+ setCursor: this.setCursor,
89
+ setKeyHandler: this.setKeyHandler,
90
+ getDOMNode: this.getDOMNode,
91
+ });
92
+ }
93
+
94
+ componentWillUnmount() {
95
+ window.removeEventListener("resize", this._throttleResizeHandler);
96
+ window.removeEventListener(
97
+ "orientationchange",
98
+ this._throttleResizeHandler,
99
+ );
100
+ this._containerResizeObserver?.disconnect();
101
+ }
102
+
103
+ _resize = () => {
104
+ const containerWidth = this._containerRef.current?.clientWidth || 0;
105
+ this.setState({containerWidth});
106
+ };
107
+
108
+ _throttleResizeHandler = () => {
109
+ if (this._throttleResize) {
110
+ return;
111
+ }
112
+
113
+ this._throttleResize = true;
114
+
115
+ setTimeout(() => {
116
+ this._resize();
117
+ this._throttleResize = false;
118
+ }, 100);
119
+ };
120
+
121
+ activate: () => void = () => {
122
+ this.props.setKeypadActive(true);
123
+ };
124
+
125
+ dismiss: () => void = () => {
126
+ this.props.setKeypadActive(false);
127
+ this.props.onDismiss?.();
128
+ };
129
+
130
+ configure: (configuration: KeypadConfiguration, cb: () => void) => void = (
131
+ configuration,
132
+ cb,
133
+ ) => {
134
+ this.setState({keypadConfig: configuration});
135
+
136
+ // TODO(matthewc)[LC-1080]: this was brought in from v1's ProvidedKeypad.
137
+ // We need to investigate whether we still need this.
138
+ // HACK(charlie): In Perseus, triggering a focus causes the keypad to
139
+ // animate into view and re-configure. We'd like to provide the option
140
+ // to re-render the re-configured keypad before animating it into view,
141
+ // to avoid jank in the animation. As such, we support passing a
142
+ // callback into `configureKeypad`. However, implementing this properly
143
+ // would require middleware, etc., so we just hack it on with
144
+ // `setTimeout` for now.
145
+ setTimeout(() => cb && cb());
146
+ };
147
+
148
+ setCursor: (cursor: Cursor) => void = (cursor) => {
149
+ this.setState({cursor});
150
+ };
151
+
152
+ setKeyHandler: (keyHandler: KeyHandler) => void = (keyHandler) => {
153
+ this.setState({keyHandler});
154
+ };
155
+
156
+ getDOMNode: () => ReturnType<typeof ReactDOM.findDOMNode> = () => {
157
+ return ReactDOM.findDOMNode(this);
158
+ };
159
+
160
+ _handleClickKey(key: Key) {
161
+ if (key === "DISMISS") {
162
+ this.dismiss();
163
+ return;
164
+ }
165
+
166
+ const cursor = this.state.keyHandler?.(key);
167
+ this.setState({cursor});
168
+ }
169
+
170
+ render(): React.ReactNode {
171
+ const {keypadActive, style} = this.props;
172
+ const {containerWidth, cursor, keypadConfig} = this.state;
173
+
174
+ const containerStyle = [
175
+ styles.keypadContainer,
176
+ // styles passed as props
177
+ ...(Array.isArray(style) ? style : [style]),
178
+ ];
179
+
180
+ const isExpression = keypadConfig?.keypadType === "EXPRESSION";
181
+ const convertDotToTimes = keypadConfig?.times;
182
+
183
+ return (
184
+ <View style={containerStyle} forwardRef={this._containerRef}>
185
+ <AphroditeCssTransitionGroup
186
+ transitionEnterTimeout={AnimationDurationInMS}
187
+ transitionLeaveTimeout={AnimationDurationInMS}
188
+ transitionStyle={{
189
+ enter: {
190
+ transform: "translate3d(0, 100%, 0)",
191
+ transition: `${AnimationDurationInMS}ms ease-out`,
192
+ },
193
+ enterActive: {
194
+ transform: "translate3d(0, 0, 0)",
195
+ },
196
+ leave: {
197
+ transform: "translate3d(0, 0, 0)",
198
+ transition: `${AnimationDurationInMS}ms ease-out`,
199
+ },
200
+ leaveActive: {
201
+ transform: "translate3d(0, 100%, 0)",
202
+ },
203
+ }}
204
+ >
205
+ {keypadActive ? (
206
+ <Keypad
207
+ onAnalyticsEvent={this.props.onAnalyticsEvent}
208
+ extraKeys={keypadConfig?.extraKeys}
209
+ onClickKey={(key) => this._handleClickKey(key)}
210
+ cursorContext={cursor?.context}
211
+ fractionsOnly={!isExpression}
212
+ convertDotToTimes={convertDotToTimes}
213
+ divisionKey={isExpression}
214
+ trigonometry={isExpression}
215
+ preAlgebra={isExpression}
216
+ logarithms={isExpression}
217
+ basicRelations={isExpression}
218
+ advancedRelations={isExpression}
219
+ expandedView={
220
+ containerWidth > expandedViewThreshold
221
+ }
222
+ showDismiss
223
+ />
224
+ ) : null}
225
+ </AphroditeCssTransitionGroup>
226
+ </View>
227
+ );
228
+ }
229
+ }
230
+
231
+ const styles = StyleSheet.create({
232
+ keypadContainer: {
233
+ bottom: 0,
234
+ left: 0,
235
+ right: 0,
236
+ position: "fixed",
237
+ },
238
+ });
239
+
240
+ export default MobileKeypadInternals;
@@ -1,237 +1,24 @@
1
- import {StyleSheet} from "aphrodite";
2
1
  import * as React from "react";
3
- import ReactDOM from "react-dom";
4
2
 
5
- import {View} from "../../fake-react-native-web/index";
6
- import AphroditeCssTransitionGroup from "../aphrodite-css-transition-group";
7
-
8
- import Keypad from "./keypad";
9
- import {expandedViewThreshold} from "./utils";
10
-
11
- import type Key from "../../data/keys";
12
- import type {
13
- Cursor,
14
- KeypadConfiguration,
15
- KeyHandler,
16
- KeypadAPI,
17
- } from "../../types";
18
- import type {AnalyticsEventHandlerFn} from "@khanacademy/perseus-core";
19
- import type {StyleType} from "@khanacademy/wonder-blocks-core";
20
-
21
- const AnimationDurationInMS = 200;
22
-
23
- type Props = {
24
- onElementMounted?: (arg1: any) => void;
25
- onDismiss?: () => void;
26
- style?: StyleType;
27
- onAnalyticsEvent: AnalyticsEventHandlerFn;
28
- setKeypadActive: (keypadActive: boolean) => void;
29
- keypadActive: boolean;
30
- };
31
-
32
- type State = {
33
- containerWidth: number;
34
- keypadConfig?: KeypadConfiguration;
35
- keyHandler?: KeyHandler;
36
- cursor?: Cursor;
37
- };
38
-
39
- /**
40
- * This is the v2 equivalent of v1's ProvidedKeypad. It follows the same
41
- * external API so that it can be hot-swapped with the v1 keypad and
42
- * is responsible for connecting the keypad with MathInput and the Renderer.
43
- *
44
- * Ideally this strategy of attaching methods on the class component for
45
- * other components to call will be replaced props/callbacks since React
46
- * doesn't support this type of code anymore (functional components
47
- * can't have methods attached to them).
48
- */
49
- class MobileKeypad extends React.Component<Props, State> implements KeypadAPI {
50
- _containerRef = React.createRef<HTMLDivElement>();
51
- _containerResizeObserver: ResizeObserver | null = null;
52
- _throttleResize = false;
53
-
54
- state: State = {
55
- containerWidth: 0,
56
- };
57
-
58
- componentDidMount() {
59
- this._resize();
60
-
61
- window.addEventListener("resize", this._throttleResizeHandler);
62
- window.addEventListener(
63
- "orientationchange",
64
- this._throttleResizeHandler,
65
- );
66
-
67
- // LC-1213: some common older browsers (as of 2023-09-07)
68
- // don't support ResizeObserver
69
- if ("ResizeObserver" in window) {
70
- this._containerResizeObserver = new window.ResizeObserver(
71
- this._throttleResizeHandler,
72
- );
73
-
74
- if (this._containerRef.current) {
75
- this._containerResizeObserver.observe(
76
- this._containerRef.current,
77
- );
78
- }
79
- }
80
-
81
- this.props.onElementMounted?.({
82
- activate: this.activate,
83
- dismiss: this.dismiss,
84
- configure: this.configure,
85
- setCursor: this.setCursor,
86
- setKeyHandler: this.setKeyHandler,
87
- getDOMNode: this.getDOMNode,
88
- });
89
- }
90
-
91
- componentWillUnmount() {
92
- window.removeEventListener("resize", this._throttleResizeHandler);
93
- window.removeEventListener(
94
- "orientationchange",
95
- this._throttleResizeHandler,
96
- );
97
- this._containerResizeObserver?.disconnect();
98
- }
99
-
100
- _resize = () => {
101
- const containerWidth = this._containerRef.current?.clientWidth || 0;
102
- this.setState({containerWidth});
103
- };
104
-
105
- _throttleResizeHandler = () => {
106
- if (this._throttleResize) {
107
- return;
108
- }
109
-
110
- this._throttleResize = true;
111
-
112
- setTimeout(() => {
113
- this._resize();
114
- this._throttleResize = false;
115
- }, 100);
116
- };
117
-
118
- activate: () => void = () => {
119
- this.props.setKeypadActive(true);
120
- };
121
-
122
- dismiss: () => void = () => {
123
- this.props.setKeypadActive(false);
124
- this.props.onDismiss?.();
125
- };
126
-
127
- configure: (configuration: KeypadConfiguration, cb: () => void) => void = (
128
- configuration,
129
- cb,
130
- ) => {
131
- this.setState({keypadConfig: configuration});
132
-
133
- // TODO(matthewc)[LC-1080]: this was brought in from v1's ProvidedKeypad.
134
- // We need to investigate whether we still need this.
135
- // HACK(charlie): In Perseus, triggering a focus causes the keypad to
136
- // animate into view and re-configure. We'd like to provide the option
137
- // to re-render the re-configured keypad before animating it into view,
138
- // to avoid jank in the animation. As such, we support passing a
139
- // callback into `configureKeypad`. However, implementing this properly
140
- // would require middleware, etc., so we just hack it on with
141
- // `setTimeout` for now.
142
- setTimeout(() => cb && cb());
143
- };
144
-
145
- setCursor: (cursor: Cursor) => void = (cursor) => {
146
- this.setState({cursor});
147
- };
148
-
149
- setKeyHandler: (keyHandler: KeyHandler) => void = (keyHandler) => {
150
- this.setState({keyHandler});
151
- };
152
-
153
- getDOMNode: () => ReturnType<typeof ReactDOM.findDOMNode> = () => {
154
- return ReactDOM.findDOMNode(this);
155
- };
156
-
157
- _handleClickKey(key: Key) {
158
- if (key === "DISMISS") {
159
- this.dismiss();
160
- return;
161
- }
162
-
163
- const cursor = this.state.keyHandler?.(key);
164
- this.setState({cursor});
165
- }
166
-
167
- render(): React.ReactNode {
168
- const {keypadActive, style} = this.props;
169
- const {containerWidth, cursor, keypadConfig} = this.state;
170
-
171
- const containerStyle = [
172
- styles.keypadContainer,
173
- // styles passed as props
174
- ...(Array.isArray(style) ? style : [style]),
175
- ];
176
-
177
- const isExpression = keypadConfig?.keypadType === "EXPRESSION";
178
- const convertDotToTimes = keypadConfig?.times;
179
-
180
- return (
181
- <View style={containerStyle} forwardRef={this._containerRef}>
182
- <AphroditeCssTransitionGroup
183
- transitionEnterTimeout={AnimationDurationInMS}
184
- transitionLeaveTimeout={AnimationDurationInMS}
185
- transitionStyle={{
186
- enter: {
187
- transform: "translate3d(0, 100%, 0)",
188
- transition: `${AnimationDurationInMS}ms ease-out`,
189
- },
190
- enterActive: {
191
- transform: "translate3d(0, 0, 0)",
192
- },
193
- leave: {
194
- transform: "translate3d(0, 0, 0)",
195
- transition: `${AnimationDurationInMS}ms ease-out`,
196
- },
197
- leaveActive: {
198
- transform: "translate3d(0, 100%, 0)",
199
- },
200
- }}
201
- >
202
- {keypadActive ? (
203
- <Keypad
204
- onAnalyticsEvent={this.props.onAnalyticsEvent}
205
- extraKeys={keypadConfig?.extraKeys}
206
- onClickKey={(key) => this._handleClickKey(key)}
207
- cursorContext={cursor?.context}
208
- fractionsOnly={!isExpression}
209
- convertDotToTimes={convertDotToTimes}
210
- divisionKey={isExpression}
211
- trigonometry={isExpression}
212
- preAlgebra={isExpression}
213
- logarithms={isExpression}
214
- basicRelations={isExpression}
215
- advancedRelations={isExpression}
216
- expandedView={
217
- containerWidth > expandedViewThreshold
218
- }
219
- showDismiss
220
- />
221
- ) : null}
222
- </AphroditeCssTransitionGroup>
223
- </View>
224
- );
225
- }
3
+ import {KeypadContext} from "../keypad-context";
4
+
5
+ import MobileKeypadInternals from "./mobile-keypad-internals";
6
+
7
+ type Props = Omit<
8
+ React.ComponentProps<typeof MobileKeypadInternals>,
9
+ "keypadActive" | "setKeypadActive"
10
+ >;
11
+
12
+ export function MobileKeypad(props: Props) {
13
+ return (
14
+ <KeypadContext.Consumer>
15
+ {({keypadActive, setKeypadActive}) => (
16
+ <MobileKeypadInternals
17
+ {...props}
18
+ keypadActive={keypadActive}
19
+ setKeypadActive={setKeypadActive}
20
+ />
21
+ )}
22
+ </KeypadContext.Consumer>
23
+ );
226
24
  }
227
-
228
- const styles = StyleSheet.create({
229
- keypadContainer: {
230
- bottom: 0,
231
- left: 0,
232
- right: 0,
233
- position: "fixed",
234
- },
235
- });
236
-
237
- export default MobileKeypad;
@@ -93,7 +93,6 @@ const Basic = ({keypadElement, setKeypadElement}) => {
93
93
  }
94
94
  }}
95
95
  onDismiss={() => {}}
96
- useV2Keypad={v2Keypad}
97
96
  onAnalyticsEvent={async (e) => action("onAnalyticsEvent")(e)}
98
97
  />
99
98
  </div>
package/src/index.ts CHANGED
@@ -27,7 +27,7 @@ export {CursorContext} from "./components/input/cursor-contexts";
27
27
  export {getCursorContext} from "./components/input/mathquill-helpers";
28
28
 
29
29
  // Wrapper around v1 and v2 mobile keypads to switch between them
30
- export {default as MobileKeypad} from "./components/keypad-switch";
30
+ export {MobileKeypad} from "./components/keypad";
31
31
  // Unwrapped v2 keypad for desktop
32
32
  export {default as DesktopKeypad} from "./components/keypad";
33
33