@khanacademy/math-input 17.0.4 → 17.0.6
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.
- package/dist/components/input/math-wrapper.d.ts +2 -2
- package/dist/components/input/mathquill-types.d.ts +49 -6
- package/dist/es/index.js +8 -6
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +8 -7
- package/dist/index.js.map +1 -1
- package/package.json +6 -3
- package/.eslintrc.js +0 -18
- package/CHANGELOG.md +0 -660
- package/less/main.less +0 -2
- package/less/overrides.less +0 -122
- package/src/components/__tests__/integration.test.tsx +0 -300
- package/src/components/aphrodite-css-transition-group/index.tsx +0 -78
- package/src/components/aphrodite-css-transition-group/transition-child.tsx +0 -192
- package/src/components/aphrodite-css-transition-group/types.ts +0 -20
- package/src/components/aphrodite-css-transition-group/util.ts +0 -97
- package/src/components/input/__tests__/context-tracking.test.ts +0 -176
- package/src/components/input/__tests__/mathquill-helpers.test.ts +0 -105
- package/src/components/input/__tests__/mathquill.test.ts +0 -747
- package/src/components/input/__tests__/test-math-wrapper.ts +0 -29
- package/src/components/input/cursor-contexts.ts +0 -37
- package/src/components/input/cursor-handle.tsx +0 -137
- package/src/components/input/cursor-styles.ts +0 -10
- package/src/components/input/drag-listener.ts +0 -79
- package/src/components/input/math-input.tsx +0 -1036
- package/src/components/input/math-wrapper.ts +0 -189
- package/src/components/input/mathquill-helpers.ts +0 -262
- package/src/components/input/mathquill-instance.ts +0 -106
- package/src/components/input/mathquill-types.ts +0 -32
- package/src/components/input/scroll-into-view.ts +0 -65
- package/src/components/key-handlers/__tests__/handle-jump-out.test.ts +0 -94
- package/src/components/key-handlers/handle-arrow.ts +0 -70
- package/src/components/key-handlers/handle-backspace.ts +0 -277
- package/src/components/key-handlers/handle-exponent.ts +0 -53
- package/src/components/key-handlers/handle-jump-out.ts +0 -107
- package/src/components/key-handlers/key-translator.ts +0 -222
- package/src/components/keypad/__tests__/__snapshots__/keypad.test.tsx.snap +0 -1913
- package/src/components/keypad/__tests__/__snapshots__/mobile-keypad.test.tsx.snap +0 -600
- package/src/components/keypad/__tests__/keypad-button.test.tsx +0 -84
- package/src/components/keypad/__tests__/keypad-v2-mathquill.test.tsx +0 -304
- package/src/components/keypad/__tests__/keypad-v2.cypress.ts +0 -16
- package/src/components/keypad/__tests__/keypad.test.tsx +0 -321
- package/src/components/keypad/__tests__/mobile-keypad.test.tsx +0 -115
- package/src/components/keypad/__tests__/test-data-tabs.ts +0 -21
- package/src/components/keypad/button-assets.tsx +0 -1880
- package/src/components/keypad/index.tsx +0 -2
- package/src/components/keypad/keypad-button.stories.tsx +0 -81
- package/src/components/keypad/keypad-button.tsx +0 -124
- package/src/components/keypad/keypad-mathquill.stories.tsx +0 -109
- package/src/components/keypad/keypad-pages/extras-page.tsx +0 -35
- package/src/components/keypad/keypad-pages/fractions-page.tsx +0 -125
- package/src/components/keypad/keypad-pages/geometry-page.tsx +0 -34
- package/src/components/keypad/keypad-pages/keypad-pages.stories.tsx +0 -37
- package/src/components/keypad/keypad-pages/numbers-page.tsx +0 -94
- package/src/components/keypad/keypad-pages/operators-page.tsx +0 -117
- package/src/components/keypad/keypad.tsx +0 -233
- package/src/components/keypad/mobile-keypad-internals.tsx +0 -240
- package/src/components/keypad/mobile-keypad.tsx +0 -24
- package/src/components/keypad/navigation-button.tsx +0 -127
- package/src/components/keypad/navigation-pad.stories.tsx +0 -26
- package/src/components/keypad/navigation-pad.tsx +0 -67
- package/src/components/keypad/shared-keys.tsx +0 -109
- package/src/components/keypad/utils.ts +0 -34
- package/src/components/keypad-context.tsx +0 -70
- package/src/components/prop-types.ts +0 -16
- package/src/components/tabbar/__tests__/tabbar.test.tsx +0 -105
- package/src/components/tabbar/icons.tsx +0 -122
- package/src/components/tabbar/index.ts +0 -1
- package/src/components/tabbar/item.tsx +0 -146
- package/src/components/tabbar/tabbar.stories.tsx +0 -83
- package/src/components/tabbar/tabbar.tsx +0 -65
- package/src/data/key-configs.ts +0 -770
- package/src/data/keys.ts +0 -123
- package/src/enums.ts +0 -27
- package/src/fake-react-native-web/index.ts +0 -11
- package/src/fake-react-native-web/text.tsx +0 -55
- package/src/fake-react-native-web/view.tsx +0 -91
- package/src/full-keypad.stories.tsx +0 -142
- package/src/full-mobile-input.stories.tsx +0 -115
- package/src/index.ts +0 -52
- package/src/types.ts +0 -70
- package/src/utils.test.ts +0 -33
- package/src/utils.ts +0 -61
- package/src/version.ts +0 -10
- package/tsconfig-build.json +0 -11
- package/tsconfig-build.tsbuildinfo +0 -1
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
|
|
3
|
-
import Keys from "../../../data/key-configs";
|
|
4
|
-
import {KeypadButton} from "../keypad-button";
|
|
5
|
-
|
|
6
|
-
import type {ClickKeyCallback} from "../../../types";
|
|
7
|
-
|
|
8
|
-
type Props = {
|
|
9
|
-
onClickKey: ClickKeyCallback;
|
|
10
|
-
preAlgebra?: boolean;
|
|
11
|
-
logarithms?: boolean;
|
|
12
|
-
basicRelations?: boolean;
|
|
13
|
-
advancedRelations?: boolean;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export default function OperatorsPage(props: Props) {
|
|
17
|
-
const {
|
|
18
|
-
onClickKey,
|
|
19
|
-
preAlgebra,
|
|
20
|
-
logarithms,
|
|
21
|
-
basicRelations,
|
|
22
|
-
advancedRelations,
|
|
23
|
-
} = props;
|
|
24
|
-
|
|
25
|
-
return (
|
|
26
|
-
<>
|
|
27
|
-
{/* Row 1 */}
|
|
28
|
-
{preAlgebra && (
|
|
29
|
-
<>
|
|
30
|
-
<KeypadButton
|
|
31
|
-
keyConfig={Keys.EXP_2}
|
|
32
|
-
onClickKey={onClickKey}
|
|
33
|
-
coord={[0, 0]}
|
|
34
|
-
/>
|
|
35
|
-
<KeypadButton
|
|
36
|
-
keyConfig={Keys.EXP}
|
|
37
|
-
onClickKey={onClickKey}
|
|
38
|
-
coord={[1, 0]}
|
|
39
|
-
/>
|
|
40
|
-
<KeypadButton
|
|
41
|
-
keyConfig={Keys.SQRT}
|
|
42
|
-
onClickKey={onClickKey}
|
|
43
|
-
coord={[2, 0]}
|
|
44
|
-
/>
|
|
45
|
-
<KeypadButton
|
|
46
|
-
keyConfig={Keys.RADICAL}
|
|
47
|
-
onClickKey={onClickKey}
|
|
48
|
-
coord={[3, 0]}
|
|
49
|
-
/>
|
|
50
|
-
</>
|
|
51
|
-
)}
|
|
52
|
-
|
|
53
|
-
{/* Row 2 */}
|
|
54
|
-
{logarithms && (
|
|
55
|
-
<>
|
|
56
|
-
<KeypadButton
|
|
57
|
-
keyConfig={Keys.LOG}
|
|
58
|
-
onClickKey={onClickKey}
|
|
59
|
-
coord={[0, 1]}
|
|
60
|
-
/>
|
|
61
|
-
<KeypadButton
|
|
62
|
-
keyConfig={Keys.LOG_N}
|
|
63
|
-
onClickKey={onClickKey}
|
|
64
|
-
coord={[1, 1]}
|
|
65
|
-
/>
|
|
66
|
-
<KeypadButton
|
|
67
|
-
keyConfig={Keys.LN}
|
|
68
|
-
onClickKey={onClickKey}
|
|
69
|
-
coord={[2, 1]}
|
|
70
|
-
/>
|
|
71
|
-
</>
|
|
72
|
-
)}
|
|
73
|
-
|
|
74
|
-
{/* Row 3 */}
|
|
75
|
-
{basicRelations && (
|
|
76
|
-
<>
|
|
77
|
-
<KeypadButton
|
|
78
|
-
keyConfig={Keys.EQUAL}
|
|
79
|
-
onClickKey={onClickKey}
|
|
80
|
-
coord={[0, 2]}
|
|
81
|
-
/>
|
|
82
|
-
<KeypadButton
|
|
83
|
-
keyConfig={Keys.LT}
|
|
84
|
-
onClickKey={onClickKey}
|
|
85
|
-
coord={[1, 2]}
|
|
86
|
-
/>
|
|
87
|
-
<KeypadButton
|
|
88
|
-
keyConfig={Keys.GT}
|
|
89
|
-
onClickKey={onClickKey}
|
|
90
|
-
coord={[2, 2]}
|
|
91
|
-
/>
|
|
92
|
-
</>
|
|
93
|
-
)}
|
|
94
|
-
|
|
95
|
-
{/* Row 4 */}
|
|
96
|
-
{advancedRelations && (
|
|
97
|
-
<>
|
|
98
|
-
<KeypadButton
|
|
99
|
-
keyConfig={Keys.NEQ}
|
|
100
|
-
onClickKey={onClickKey}
|
|
101
|
-
coord={[0, 3]}
|
|
102
|
-
/>
|
|
103
|
-
<KeypadButton
|
|
104
|
-
keyConfig={Keys.LEQ}
|
|
105
|
-
onClickKey={onClickKey}
|
|
106
|
-
coord={[1, 3]}
|
|
107
|
-
/>
|
|
108
|
-
<KeypadButton
|
|
109
|
-
keyConfig={Keys.GEQ}
|
|
110
|
-
onClickKey={onClickKey}
|
|
111
|
-
coord={[2, 3]}
|
|
112
|
-
/>
|
|
113
|
-
</>
|
|
114
|
-
)}
|
|
115
|
-
</>
|
|
116
|
-
);
|
|
117
|
-
}
|
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
import Color from "@khanacademy/wonder-blocks-color";
|
|
2
|
-
import {View} from "@khanacademy/wonder-blocks-core";
|
|
3
|
-
import {StyleSheet} from "aphrodite";
|
|
4
|
-
import * as React from "react";
|
|
5
|
-
import {useEffect} from "react";
|
|
6
|
-
|
|
7
|
-
import Tabbar from "../tabbar";
|
|
8
|
-
|
|
9
|
-
import ExtrasPage from "./keypad-pages/extras-page";
|
|
10
|
-
import FractionsPage from "./keypad-pages/fractions-page";
|
|
11
|
-
import GeometryPage from "./keypad-pages/geometry-page";
|
|
12
|
-
import NumbersPage from "./keypad-pages/numbers-page";
|
|
13
|
-
import OperatorsPage from "./keypad-pages/operators-page";
|
|
14
|
-
import NavigationPad from "./navigation-pad";
|
|
15
|
-
import SharedKeys from "./shared-keys";
|
|
16
|
-
import {expandedViewThreshold} from "./utils";
|
|
17
|
-
|
|
18
|
-
import type Key from "../../data/keys";
|
|
19
|
-
import type {ClickKeyCallback, KeypadPageType} from "../../types";
|
|
20
|
-
import type {CursorContext} from "../input/cursor-contexts";
|
|
21
|
-
import type {AnalyticsEventHandlerFn} from "@khanacademy/perseus-core";
|
|
22
|
-
|
|
23
|
-
export type Props = {
|
|
24
|
-
extraKeys: ReadonlyArray<Key>;
|
|
25
|
-
cursorContext?: typeof CursorContext[keyof typeof CursorContext];
|
|
26
|
-
showDismiss?: boolean;
|
|
27
|
-
expandedView?: boolean;
|
|
28
|
-
|
|
29
|
-
convertDotToTimes?: boolean;
|
|
30
|
-
divisionKey?: boolean;
|
|
31
|
-
trigonometry?: boolean;
|
|
32
|
-
preAlgebra?: boolean;
|
|
33
|
-
logarithms?: boolean;
|
|
34
|
-
basicRelations?: boolean;
|
|
35
|
-
advancedRelations?: boolean;
|
|
36
|
-
fractionsOnly?: boolean;
|
|
37
|
-
|
|
38
|
-
onClickKey: ClickKeyCallback;
|
|
39
|
-
onAnalyticsEvent: AnalyticsEventHandlerFn;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const defaultProps = {
|
|
43
|
-
extraKeys: [],
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
function getAvailableTabs(props: Props): ReadonlyArray<KeypadPageType> {
|
|
47
|
-
// We don't want to show any available tabs on the fractions keypad
|
|
48
|
-
if (props.fractionsOnly) {
|
|
49
|
-
return [];
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const tabs: Array<KeypadPageType> = ["Numbers"];
|
|
53
|
-
if (
|
|
54
|
-
// OperatorsButtonSets
|
|
55
|
-
props.preAlgebra ||
|
|
56
|
-
props.logarithms ||
|
|
57
|
-
props.basicRelations ||
|
|
58
|
-
props.advancedRelations
|
|
59
|
-
) {
|
|
60
|
-
tabs.push("Operators");
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (props.trigonometry) {
|
|
64
|
-
tabs.push("Geometry");
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (props.extraKeys?.length) {
|
|
68
|
-
tabs.push("Extras");
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return tabs;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// The main (v2) Keypad. Use this component to present an accessible, onscreen
|
|
75
|
-
// keypad to learners for entering math expressions.
|
|
76
|
-
export default function Keypad(props: Props) {
|
|
77
|
-
// If we're using the Fractions keypad, we want to default select that page
|
|
78
|
-
// Otherwise, we want to default to the Numbers page
|
|
79
|
-
const defaultSelectedPage = props.fractionsOnly ? "Fractions" : "Numbers";
|
|
80
|
-
const [selectedPage, setSelectedPage] =
|
|
81
|
-
React.useState<KeypadPageType>(defaultSelectedPage);
|
|
82
|
-
const [isMounted, setIsMounted] = React.useState<boolean>(false);
|
|
83
|
-
|
|
84
|
-
// We don't want any tabs available on mobile fractions keypad
|
|
85
|
-
const availableTabs = getAvailableTabs(props);
|
|
86
|
-
|
|
87
|
-
const {
|
|
88
|
-
onClickKey,
|
|
89
|
-
cursorContext,
|
|
90
|
-
extraKeys,
|
|
91
|
-
convertDotToTimes,
|
|
92
|
-
divisionKey,
|
|
93
|
-
preAlgebra,
|
|
94
|
-
logarithms,
|
|
95
|
-
basicRelations,
|
|
96
|
-
advancedRelations,
|
|
97
|
-
showDismiss,
|
|
98
|
-
onAnalyticsEvent,
|
|
99
|
-
fractionsOnly,
|
|
100
|
-
expandedView,
|
|
101
|
-
} = props;
|
|
102
|
-
|
|
103
|
-
// Use a different grid for our fraction keypad
|
|
104
|
-
const gridStyle = fractionsOnly
|
|
105
|
-
? styles.fractionsGrid
|
|
106
|
-
: styles.expressionGrid;
|
|
107
|
-
|
|
108
|
-
// This useEffect is only used to ensure that we can test the keypad in storybook
|
|
109
|
-
useEffect(() => {
|
|
110
|
-
setSelectedPage(defaultSelectedPage);
|
|
111
|
-
}, [fractionsOnly, defaultSelectedPage]);
|
|
112
|
-
|
|
113
|
-
useEffect(() => {
|
|
114
|
-
if (!isMounted) {
|
|
115
|
-
onAnalyticsEvent({
|
|
116
|
-
type: "math-input:keypad-opened",
|
|
117
|
-
payload: {virtualKeypadVersion: "MATH_INPUT_KEYPAD_V2"},
|
|
118
|
-
});
|
|
119
|
-
setIsMounted(true);
|
|
120
|
-
}
|
|
121
|
-
return () => {
|
|
122
|
-
if (isMounted) {
|
|
123
|
-
onAnalyticsEvent({
|
|
124
|
-
type: "math-input:keypad-closed",
|
|
125
|
-
payload: {virtualKeypadVersion: "MATH_INPUT_KEYPAD_V2"},
|
|
126
|
-
});
|
|
127
|
-
setIsMounted(false);
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
}, [onAnalyticsEvent, isMounted]);
|
|
131
|
-
|
|
132
|
-
return (
|
|
133
|
-
<View style={expandedView ? styles.keypadOuterContainer : null}>
|
|
134
|
-
<View
|
|
135
|
-
style={[
|
|
136
|
-
styles.wrapper,
|
|
137
|
-
expandedView ? styles.expandedWrapper : null,
|
|
138
|
-
]}
|
|
139
|
-
>
|
|
140
|
-
<Tabbar
|
|
141
|
-
items={availableTabs}
|
|
142
|
-
selectedItem={selectedPage}
|
|
143
|
-
onSelectItem={(newSelectedPage: KeypadPageType) => {
|
|
144
|
-
setSelectedPage(newSelectedPage);
|
|
145
|
-
}}
|
|
146
|
-
onClickClose={
|
|
147
|
-
showDismiss ? () => onClickKey("DISMISS") : undefined
|
|
148
|
-
}
|
|
149
|
-
/>
|
|
150
|
-
|
|
151
|
-
<View style={styles.keypadInnerContainer}>
|
|
152
|
-
<View
|
|
153
|
-
style={[styles.keypadGrid, gridStyle]}
|
|
154
|
-
tabIndex={0}
|
|
155
|
-
aria-label="Keypad"
|
|
156
|
-
>
|
|
157
|
-
{selectedPage === "Fractions" && (
|
|
158
|
-
<FractionsPage
|
|
159
|
-
onClickKey={onClickKey}
|
|
160
|
-
cursorContext={cursorContext}
|
|
161
|
-
/>
|
|
162
|
-
)}
|
|
163
|
-
{selectedPage === "Numbers" && (
|
|
164
|
-
<NumbersPage onClickKey={onClickKey} />
|
|
165
|
-
)}
|
|
166
|
-
{selectedPage === "Extras" && (
|
|
167
|
-
<ExtrasPage
|
|
168
|
-
onClickKey={onClickKey}
|
|
169
|
-
extraKeys={extraKeys}
|
|
170
|
-
/>
|
|
171
|
-
)}
|
|
172
|
-
{selectedPage === "Operators" && (
|
|
173
|
-
<OperatorsPage
|
|
174
|
-
onClickKey={onClickKey}
|
|
175
|
-
preAlgebra={preAlgebra}
|
|
176
|
-
logarithms={logarithms}
|
|
177
|
-
basicRelations={basicRelations}
|
|
178
|
-
advancedRelations={advancedRelations}
|
|
179
|
-
/>
|
|
180
|
-
)}
|
|
181
|
-
{selectedPage === "Geometry" && (
|
|
182
|
-
<GeometryPage onClickKey={onClickKey} />
|
|
183
|
-
)}
|
|
184
|
-
{!fractionsOnly && (
|
|
185
|
-
<SharedKeys
|
|
186
|
-
onClickKey={onClickKey}
|
|
187
|
-
cursorContext={cursorContext}
|
|
188
|
-
convertDotToTimes={convertDotToTimes}
|
|
189
|
-
divisionKey={divisionKey}
|
|
190
|
-
selectedPage={selectedPage}
|
|
191
|
-
/>
|
|
192
|
-
)}
|
|
193
|
-
</View>
|
|
194
|
-
{expandedView && <NavigationPad onClickKey={onClickKey} />}
|
|
195
|
-
</View>
|
|
196
|
-
</View>
|
|
197
|
-
</View>
|
|
198
|
-
);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
Keypad.defaultProps = defaultProps;
|
|
202
|
-
|
|
203
|
-
const styles = StyleSheet.create({
|
|
204
|
-
keypadOuterContainer: {
|
|
205
|
-
display: "flex",
|
|
206
|
-
alignItems: "center",
|
|
207
|
-
},
|
|
208
|
-
wrapper: {
|
|
209
|
-
background: Color.white,
|
|
210
|
-
},
|
|
211
|
-
expandedWrapper: {
|
|
212
|
-
borderWidth: "1px 1px 0 1px",
|
|
213
|
-
borderColor: Color.offBlack32,
|
|
214
|
-
maxWidth: expandedViewThreshold,
|
|
215
|
-
borderRadius: "3px 3px 0 0",
|
|
216
|
-
},
|
|
217
|
-
keypadInnerContainer: {
|
|
218
|
-
display: "flex",
|
|
219
|
-
flexDirection: "row",
|
|
220
|
-
backgroundColor: "#DBDCDD",
|
|
221
|
-
},
|
|
222
|
-
keypadGrid: {
|
|
223
|
-
display: "grid",
|
|
224
|
-
gridTemplateRows: "repeat(4, 1fr)",
|
|
225
|
-
flex: 1,
|
|
226
|
-
},
|
|
227
|
-
expressionGrid: {
|
|
228
|
-
gridTemplateColumns: "repeat(6, 1fr)",
|
|
229
|
-
},
|
|
230
|
-
fractionsGrid: {
|
|
231
|
-
gridTemplateColumns: "repeat(5, 1fr)",
|
|
232
|
-
},
|
|
233
|
-
});
|
|
@@ -1,240 +0,0 @@
|
|
|
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,24 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
|
|
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
|
-
);
|
|
24
|
-
}
|