@khanacademy/math-input 15.1.0 → 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.
- package/CHANGELOG.md +11 -0
- package/dist/components/keypad/index.d.ts +1 -1
- package/dist/components/keypad/mobile-keypad-internals.d.ts +49 -0
- package/dist/components/keypad/mobile-keypad.d.ts +4 -48
- package/dist/es/index.js +168 -4740
- package/dist/es/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +166 -4722
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/__tests__/integration.test.tsx +2 -3
- package/src/components/keypad/__tests__/mobile-keypad.test.tsx +8 -8
- package/src/components/keypad/index.tsx +1 -1
- package/src/components/keypad/mobile-keypad-internals.tsx +240 -0
- package/src/components/keypad/mobile-keypad.tsx +21 -234
- package/src/full-mobile-input.stories.tsx +0 -1
- package/src/index.ts +1 -1
- package/tsconfig-build.tsbuildinfo +1 -1
- package/dist/components/keypad-legacy/compute-layout-parameters.d.ts +0 -28
- package/dist/components/keypad-legacy/corner-decal.d.ts +0 -12
- package/dist/components/keypad-legacy/echo-manager.d.ts +0 -17
- package/dist/components/keypad-legacy/empty-keypad-button.d.ts +0 -13
- package/dist/components/keypad-legacy/expression-keypad.d.ts +0 -21
- package/dist/components/keypad-legacy/fraction-keypad.d.ts +0 -21
- package/dist/components/keypad-legacy/gesture-manager.d.ts +0 -86
- package/dist/components/keypad-legacy/gesture-state-machine.d.ts +0 -105
- package/dist/components/keypad-legacy/icon.d.ts +0 -15
- package/dist/components/keypad-legacy/index.d.ts +0 -1
- package/dist/components/keypad-legacy/keypad-button.d.ts +0 -53
- package/dist/components/keypad-legacy/keypad-container.d.ts +0 -41
- package/dist/components/keypad-legacy/keypad.d.ts +0 -31
- package/dist/components/keypad-legacy/many-keypad-button.d.ts +0 -15
- package/dist/components/keypad-legacy/math-icon.d.ts +0 -16
- package/dist/components/keypad-legacy/multi-symbol-grid.d.ts +0 -14
- package/dist/components/keypad-legacy/multi-symbol-popover.d.ts +0 -12
- package/dist/components/keypad-legacy/navigation-pad.d.ts +0 -14
- package/dist/components/keypad-legacy/node-manager.d.ts +0 -49
- package/dist/components/keypad-legacy/popover-manager.d.ts +0 -13
- package/dist/components/keypad-legacy/popover-state-machine.d.ts +0 -68
- package/dist/components/keypad-legacy/provided-keypad.d.ts +0 -28
- package/dist/components/keypad-legacy/store/actions.d.ts +0 -55
- package/dist/components/keypad-legacy/store/echo-reducer.d.ts +0 -4
- package/dist/components/keypad-legacy/store/index.d.ts +0 -9
- package/dist/components/keypad-legacy/store/input-reducer.d.ts +0 -4
- package/dist/components/keypad-legacy/store/keypad-reducer.d.ts +0 -4
- package/dist/components/keypad-legacy/store/layout-reducer.d.ts +0 -4
- package/dist/components/keypad-legacy/store/shared.d.ts +0 -7
- package/dist/components/keypad-legacy/store/types.d.ts +0 -47
- package/dist/components/keypad-legacy/styles.d.ts +0 -5
- package/dist/components/keypad-legacy/svg-icon.d.ts +0 -12
- package/dist/components/keypad-legacy/text-icon.d.ts +0 -13
- package/dist/components/keypad-legacy/touchable-keypad-button.d.ts +0 -37
- package/dist/components/keypad-legacy/two-page-keypad.d.ts +0 -21
- package/dist/components/keypad-legacy/z-indexes.d.ts +0 -7
- package/dist/components/keypad-switch.d.ts +0 -12
- package/src/components/keypad-legacy/__tests__/gesture-state-machine.test.ts +0 -441
- package/src/components/keypad-legacy/__tests__/node-manager.test.ts +0 -89
- package/src/components/keypad-legacy/compute-layout-parameters.ts +0 -205
- package/src/components/keypad-legacy/corner-decal.tsx +0 -56
- package/src/components/keypad-legacy/echo-manager.tsx +0 -152
- package/src/components/keypad-legacy/empty-keypad-button.tsx +0 -58
- package/src/components/keypad-legacy/expression-keypad.tsx +0 -315
- package/src/components/keypad-legacy/fraction-keypad.tsx +0 -180
- package/src/components/keypad-legacy/gesture-manager.ts +0 -255
- package/src/components/keypad-legacy/gesture-state-machine.ts +0 -329
- package/src/components/keypad-legacy/icon.tsx +0 -72
- package/src/components/keypad-legacy/iconography/arrow.js +0 -22
- package/src/components/keypad-legacy/iconography/backspace.js +0 -29
- package/src/components/keypad-legacy/iconography/cdot.js +0 -29
- package/src/components/keypad-legacy/iconography/cos.js +0 -30
- package/src/components/keypad-legacy/iconography/cube-root.js +0 -36
- package/src/components/keypad-legacy/iconography/dismiss.js +0 -25
- package/src/components/keypad-legacy/iconography/divide.js +0 -34
- package/src/components/keypad-legacy/iconography/down.js +0 -16
- package/src/components/keypad-legacy/iconography/equal.js +0 -33
- package/src/components/keypad-legacy/iconography/exp-2.js +0 -29
- package/src/components/keypad-legacy/iconography/exp-3.js +0 -29
- package/src/components/keypad-legacy/iconography/exp.js +0 -29
- package/src/components/keypad-legacy/iconography/frac.js +0 -44
- package/src/components/keypad-legacy/iconography/geq.js +0 -33
- package/src/components/keypad-legacy/iconography/gt.js +0 -33
- package/src/components/keypad-legacy/iconography/index.js +0 -45
- package/src/components/keypad-legacy/iconography/jump-into-numerator.js +0 -41
- package/src/components/keypad-legacy/iconography/jump-out-base.js +0 -30
- package/src/components/keypad-legacy/iconography/jump-out-denominator.js +0 -41
- package/src/components/keypad-legacy/iconography/jump-out-exponent.js +0 -30
- package/src/components/keypad-legacy/iconography/jump-out-numerator.js +0 -41
- package/src/components/keypad-legacy/iconography/jump-out-parentheses.js +0 -33
- package/src/components/keypad-legacy/iconography/left-paren.js +0 -33
- package/src/components/keypad-legacy/iconography/left.js +0 -16
- package/src/components/keypad-legacy/iconography/leq.js +0 -33
- package/src/components/keypad-legacy/iconography/ln.js +0 -29
- package/src/components/keypad-legacy/iconography/log-n.js +0 -29
- package/src/components/keypad-legacy/iconography/log.js +0 -29
- package/src/components/keypad-legacy/iconography/lt.js +0 -33
- package/src/components/keypad-legacy/iconography/minus.js +0 -32
- package/src/components/keypad-legacy/iconography/neq.js +0 -33
- package/src/components/keypad-legacy/iconography/parens.js +0 -33
- package/src/components/keypad-legacy/iconography/percent.js +0 -49
- package/src/components/keypad-legacy/iconography/period.js +0 -26
- package/src/components/keypad-legacy/iconography/plus.js +0 -32
- package/src/components/keypad-legacy/iconography/radical.js +0 -36
- package/src/components/keypad-legacy/iconography/right-paren.js +0 -33
- package/src/components/keypad-legacy/iconography/right.js +0 -16
- package/src/components/keypad-legacy/iconography/sin.js +0 -30
- package/src/components/keypad-legacy/iconography/sqrt.js +0 -32
- package/src/components/keypad-legacy/iconography/tan.js +0 -30
- package/src/components/keypad-legacy/iconography/times.js +0 -33
- package/src/components/keypad-legacy/iconography/up.js +0 -16
- package/src/components/keypad-legacy/index.ts +0 -1
- package/src/components/keypad-legacy/keypad-button.tsx +0 -368
- package/src/components/keypad-legacy/keypad-container.tsx +0 -358
- package/src/components/keypad-legacy/keypad.tsx +0 -162
- package/src/components/keypad-legacy/many-keypad-button.tsx +0 -54
- package/src/components/keypad-legacy/math-icon.tsx +0 -66
- package/src/components/keypad-legacy/multi-symbol-grid.tsx +0 -182
- package/src/components/keypad-legacy/multi-symbol-popover.tsx +0 -58
- package/src/components/keypad-legacy/navigation-pad.tsx +0 -140
- package/src/components/keypad-legacy/node-manager.ts +0 -133
- package/src/components/keypad-legacy/popover-manager.tsx +0 -73
- package/src/components/keypad-legacy/popover-state-machine.ts +0 -184
- package/src/components/keypad-legacy/provided-keypad.tsx +0 -136
- package/src/components/keypad-legacy/store/actions.ts +0 -155
- package/src/components/keypad-legacy/store/echo-reducer.ts +0 -57
- package/src/components/keypad-legacy/store/index.ts +0 -110
- package/src/components/keypad-legacy/store/input-reducer.ts +0 -55
- package/src/components/keypad-legacy/store/keypad-reducer.ts +0 -58
- package/src/components/keypad-legacy/store/layout-reducer.test.ts +0 -171
- package/src/components/keypad-legacy/store/layout-reducer.ts +0 -129
- package/src/components/keypad-legacy/store/shared.ts +0 -12
- package/src/components/keypad-legacy/store/types.ts +0 -78
- package/src/components/keypad-legacy/styles.ts +0 -38
- package/src/components/keypad-legacy/svg-icon.tsx +0 -24
- package/src/components/keypad-legacy/text-icon.tsx +0 -53
- package/src/components/keypad-legacy/touchable-keypad-button.tsx +0 -163
- package/src/components/keypad-legacy/two-page-keypad.tsx +0 -115
- package/src/components/keypad-legacy/z-indexes.ts +0 -8
- package/src/components/keypad-switch.tsx +0 -42
|
@@ -1,358 +0,0 @@
|
|
|
1
|
-
import {StyleSheet} from "aphrodite";
|
|
2
|
-
import * as React from "react";
|
|
3
|
-
import {connect} from "react-redux";
|
|
4
|
-
|
|
5
|
-
import {LayoutMode, KeypadType} from "../../enums";
|
|
6
|
-
import {View} from "../../fake-react-native-web/index";
|
|
7
|
-
import {
|
|
8
|
-
innerBorderColor,
|
|
9
|
-
innerBorderStyle,
|
|
10
|
-
innerBorderWidthPx,
|
|
11
|
-
compactKeypadBorderRadiusPx,
|
|
12
|
-
} from "../common-style";
|
|
13
|
-
|
|
14
|
-
import ExpressionKeypad from "./expression-keypad";
|
|
15
|
-
import FractionKeypad from "./fraction-keypad";
|
|
16
|
-
import NavigationPad from "./navigation-pad";
|
|
17
|
-
import {setPageSize} from "./store/actions";
|
|
18
|
-
import Styles from "./styles";
|
|
19
|
-
import * as zIndexes from "./z-indexes";
|
|
20
|
-
|
|
21
|
-
import type {State as ReduxState} from "./store/types";
|
|
22
|
-
import type {StyleType} from "@khanacademy/wonder-blocks-core";
|
|
23
|
-
|
|
24
|
-
const {row, centered, fullWidth} = Styles;
|
|
25
|
-
|
|
26
|
-
interface ReduxProps {
|
|
27
|
-
active?: boolean;
|
|
28
|
-
extraKeys?: ReadonlyArray<string>;
|
|
29
|
-
keypadType?: KeypadType;
|
|
30
|
-
layoutMode?: LayoutMode;
|
|
31
|
-
navigationPadEnabled?: boolean;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
interface Props extends ReduxProps {
|
|
35
|
-
onDismiss?: () => void;
|
|
36
|
-
onElementMounted: (element: any) => void;
|
|
37
|
-
onPageSizeChange?: (
|
|
38
|
-
pageWidth: number,
|
|
39
|
-
pageHeight: number,
|
|
40
|
-
containerWidth: number,
|
|
41
|
-
containerHeight: number,
|
|
42
|
-
) => void;
|
|
43
|
-
style?: StyleType;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
type State = {
|
|
47
|
-
hasBeenActivated: boolean;
|
|
48
|
-
viewportWidth: string | number;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
// eslint-disable-next-line react/no-unsafe
|
|
52
|
-
class KeypadContainer extends React.Component<Props, State> {
|
|
53
|
-
_containerRef = React.createRef<HTMLDivElement>();
|
|
54
|
-
_containerResizeObserver: ResizeObserver | null = null;
|
|
55
|
-
_resizeTimeout: number | null | undefined;
|
|
56
|
-
hasMounted: boolean | undefined;
|
|
57
|
-
|
|
58
|
-
state = {
|
|
59
|
-
hasBeenActivated: false,
|
|
60
|
-
viewportWidth: "100vw",
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
UNSAFE_componentWillMount() {
|
|
64
|
-
if (this.props.active) {
|
|
65
|
-
this.setState({
|
|
66
|
-
hasBeenActivated: this.props.active,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
componentDidMount() {
|
|
72
|
-
// Relay the initial size metrics.
|
|
73
|
-
this._onResize();
|
|
74
|
-
|
|
75
|
-
// And update it on resize.
|
|
76
|
-
window.addEventListener("resize", this._throttleResizeHandler);
|
|
77
|
-
window.addEventListener(
|
|
78
|
-
"orientationchange",
|
|
79
|
-
this._throttleResizeHandler,
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
// LC-1213: some common older browsers (as of 2023-09-07)
|
|
83
|
-
// don't support ResizeObserver
|
|
84
|
-
if ("ResizeObserver" in window) {
|
|
85
|
-
this._containerResizeObserver = new window.ResizeObserver(
|
|
86
|
-
this._throttleResizeHandler,
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
if (this._containerRef.current) {
|
|
90
|
-
this._containerResizeObserver.observe(
|
|
91
|
-
this._containerRef.current,
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
98
|
-
if (!this.state.hasBeenActivated && nextProps.active) {
|
|
99
|
-
this.setState({
|
|
100
|
-
hasBeenActivated: true,
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
componentDidUpdate(prevProps) {
|
|
106
|
-
if (prevProps.active && !this.props.active) {
|
|
107
|
-
this.props.onDismiss && this.props.onDismiss();
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
componentWillUnmount() {
|
|
112
|
-
window.removeEventListener("resize", this._throttleResizeHandler);
|
|
113
|
-
window.removeEventListener(
|
|
114
|
-
"orientationchange",
|
|
115
|
-
this._throttleResizeHandler,
|
|
116
|
-
);
|
|
117
|
-
this._containerResizeObserver?.disconnect();
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
_throttleResizeHandler = () => {
|
|
121
|
-
// Throttle the resize callbacks.
|
|
122
|
-
// https://developer.mozilla.org/en-US/docs/Web/Events/resize
|
|
123
|
-
if (this._resizeTimeout == null) {
|
|
124
|
-
this._resizeTimeout = window.setTimeout(() => {
|
|
125
|
-
this._resizeTimeout = null;
|
|
126
|
-
|
|
127
|
-
this._onResize();
|
|
128
|
-
}, 66);
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
_onResize = () => {
|
|
133
|
-
// Whenever the page resizes, we need to force an update, as the button
|
|
134
|
-
// heights and keypad width are computed based on horizontal space.
|
|
135
|
-
this.setState({
|
|
136
|
-
viewportWidth: window.innerWidth,
|
|
137
|
-
});
|
|
138
|
-
const containerWidth = this._containerRef.current?.clientWidth || 0;
|
|
139
|
-
const containerHeight = this._containerRef.current?.clientHeight || 0;
|
|
140
|
-
this.props.onPageSizeChange?.(
|
|
141
|
-
window.innerWidth,
|
|
142
|
-
window.innerHeight,
|
|
143
|
-
containerWidth,
|
|
144
|
-
containerHeight,
|
|
145
|
-
);
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
renderKeypad = () => {
|
|
149
|
-
const {extraKeys, keypadType, layoutMode, navigationPadEnabled} =
|
|
150
|
-
this.props;
|
|
151
|
-
|
|
152
|
-
const keypadProps = {
|
|
153
|
-
extraKeys,
|
|
154
|
-
// HACK(charlie): In order to properly round the corners of the
|
|
155
|
-
// compact keypad, we need to instruct some of our child views to
|
|
156
|
-
// crop themselves. At least we're colocating all the layout
|
|
157
|
-
// information in this component, though.
|
|
158
|
-
roundTopLeft:
|
|
159
|
-
layoutMode === LayoutMode.COMPACT && !navigationPadEnabled,
|
|
160
|
-
roundTopRight: layoutMode === LayoutMode.COMPACT,
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
// Select the appropriate keyboard given the type.
|
|
164
|
-
// TODO(charlie): In the future, we might want to move towards a
|
|
165
|
-
// data-driven approach to defining keyboard layouts, and have a
|
|
166
|
-
// generic keyboard that takes some "keyboard data" and renders it.
|
|
167
|
-
// However, the keyboards differ pretty heavily right now and it's not
|
|
168
|
-
// clear what that format would look like exactly. Plus, there aren't
|
|
169
|
-
// very many of them. So to keep us moving, we'll just hardcode.
|
|
170
|
-
switch (keypadType) {
|
|
171
|
-
case KeypadType.FRACTION:
|
|
172
|
-
return <FractionKeypad {...keypadProps} />;
|
|
173
|
-
|
|
174
|
-
case KeypadType.EXPRESSION:
|
|
175
|
-
return <ExpressionKeypad {...keypadProps} />;
|
|
176
|
-
|
|
177
|
-
default:
|
|
178
|
-
throw new Error("Invalid keypad type: " + keypadType);
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
render() {
|
|
183
|
-
const {
|
|
184
|
-
active,
|
|
185
|
-
layoutMode,
|
|
186
|
-
navigationPadEnabled,
|
|
187
|
-
onElementMounted,
|
|
188
|
-
style,
|
|
189
|
-
} = this.props;
|
|
190
|
-
const {hasBeenActivated} = this.state;
|
|
191
|
-
|
|
192
|
-
// NOTE(charlie): We render the transforms as pure inline styles to
|
|
193
|
-
// avoid an Aphrodite bug in mobile Safari.
|
|
194
|
-
// See: https://github.com/Khan/aphrodite/issues/68.
|
|
195
|
-
let dynamicStyle = {
|
|
196
|
-
...(active ? inlineStyles.active : inlineStyles.hidden),
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
if (!active && !hasBeenActivated) {
|
|
200
|
-
dynamicStyle = {
|
|
201
|
-
...dynamicStyle,
|
|
202
|
-
...inlineStyles.invisible,
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
const keypadContainerStyle = [
|
|
207
|
-
row,
|
|
208
|
-
centered,
|
|
209
|
-
fullWidth,
|
|
210
|
-
styles.keypadContainer,
|
|
211
|
-
...(Array.isArray(style) ? style : [style]),
|
|
212
|
-
];
|
|
213
|
-
|
|
214
|
-
const keypadStyle = [
|
|
215
|
-
row,
|
|
216
|
-
styles.keypadBorder,
|
|
217
|
-
layoutMode === LayoutMode.FULLSCREEN
|
|
218
|
-
? styles.fullscreen
|
|
219
|
-
: styles.compact,
|
|
220
|
-
];
|
|
221
|
-
|
|
222
|
-
// TODO(charlie): When the keypad is shorter than the width of the
|
|
223
|
-
// screen, add a border on its left and right edges, and round out the
|
|
224
|
-
// corners.
|
|
225
|
-
return (
|
|
226
|
-
<View
|
|
227
|
-
style={keypadContainerStyle}
|
|
228
|
-
dynamicStyle={dynamicStyle}
|
|
229
|
-
extraClassName="keypad-container"
|
|
230
|
-
forwardRef={this._containerRef}
|
|
231
|
-
>
|
|
232
|
-
<View
|
|
233
|
-
style={keypadStyle}
|
|
234
|
-
ref={(element) => {
|
|
235
|
-
if (!this.hasMounted && element) {
|
|
236
|
-
this.hasMounted = true;
|
|
237
|
-
onElementMounted(element);
|
|
238
|
-
}
|
|
239
|
-
}}
|
|
240
|
-
>
|
|
241
|
-
{navigationPadEnabled && (
|
|
242
|
-
<NavigationPad
|
|
243
|
-
roundTopLeft={layoutMode === LayoutMode.COMPACT}
|
|
244
|
-
style={styles.navigationPadContainer}
|
|
245
|
-
/>
|
|
246
|
-
)}
|
|
247
|
-
<View style={styles.keypadLayout}>
|
|
248
|
-
{this.renderKeypad()}
|
|
249
|
-
</View>
|
|
250
|
-
</View>
|
|
251
|
-
</View>
|
|
252
|
-
);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const keypadAnimationDurationMs = 300;
|
|
257
|
-
const borderWidthPx = 1;
|
|
258
|
-
|
|
259
|
-
const styles = StyleSheet.create({
|
|
260
|
-
keypadContainer: {
|
|
261
|
-
bottom: 0,
|
|
262
|
-
left: 0,
|
|
263
|
-
right: 0,
|
|
264
|
-
position: "fixed",
|
|
265
|
-
transition: `${keypadAnimationDurationMs}ms ease-out`,
|
|
266
|
-
transitionProperty: "transform",
|
|
267
|
-
zIndex: zIndexes.keypad,
|
|
268
|
-
},
|
|
269
|
-
|
|
270
|
-
keypadBorder: {
|
|
271
|
-
boxShadow: "0 1px 4px 0 rgba(0, 0, 0, 0.1)",
|
|
272
|
-
borderColor: "rgba(0, 0, 0, 0.2)",
|
|
273
|
-
borderStyle: "solid",
|
|
274
|
-
},
|
|
275
|
-
|
|
276
|
-
fullscreen: {
|
|
277
|
-
borderTopWidth: borderWidthPx,
|
|
278
|
-
},
|
|
279
|
-
|
|
280
|
-
compact: {
|
|
281
|
-
borderTopRightRadius: compactKeypadBorderRadiusPx,
|
|
282
|
-
borderTopLeftRadius: compactKeypadBorderRadiusPx,
|
|
283
|
-
|
|
284
|
-
borderTopWidth: borderWidthPx,
|
|
285
|
-
borderRightWidth: borderWidthPx,
|
|
286
|
-
borderLeftWidth: borderWidthPx,
|
|
287
|
-
},
|
|
288
|
-
|
|
289
|
-
navigationPadContainer: {
|
|
290
|
-
// Add a separator between the navigation pad and the keypad.
|
|
291
|
-
borderRight:
|
|
292
|
-
`${innerBorderWidthPx}px ${innerBorderStyle} ` +
|
|
293
|
-
`${innerBorderColor}`,
|
|
294
|
-
boxSizing: "content-box",
|
|
295
|
-
},
|
|
296
|
-
|
|
297
|
-
// Defer to the navigation pad, such that the navigation pad is always
|
|
298
|
-
// rendered at full-width, and the keypad takes up just the remaining space.
|
|
299
|
-
// TODO(charlie): Avoid shrinking the keys and, instead, make the keypad
|
|
300
|
-
// scrollable.
|
|
301
|
-
keypadLayout: {
|
|
302
|
-
flexGrow: 1,
|
|
303
|
-
// Avoid unitless flex-basis, per: https://philipwalton.com/articles/normalizing-cross-browser-flexbox-bugs/
|
|
304
|
-
flexBasis: "0%",
|
|
305
|
-
},
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
// Note: these don't go through an autoprefixer/aphrodite.
|
|
309
|
-
const inlineStyles = {
|
|
310
|
-
// If the keypad is yet to have ever been activated, we keep it invisible
|
|
311
|
-
// so as to avoid, e.g., the keypad flashing at the bottom of the page
|
|
312
|
-
// during the initial render.
|
|
313
|
-
invisible: {
|
|
314
|
-
visibility: "hidden",
|
|
315
|
-
},
|
|
316
|
-
|
|
317
|
-
hidden: {
|
|
318
|
-
transform: "translate3d(0, 100%, 0)",
|
|
319
|
-
},
|
|
320
|
-
|
|
321
|
-
active: {
|
|
322
|
-
transform: "translate3d(0, 0, 0)",
|
|
323
|
-
},
|
|
324
|
-
};
|
|
325
|
-
|
|
326
|
-
const mapStateToProps = (state: ReduxState): ReduxProps => {
|
|
327
|
-
return {
|
|
328
|
-
extraKeys: state.keypad.extraKeys,
|
|
329
|
-
keypadType: state.keypad.keypadType,
|
|
330
|
-
active: state.keypad.active,
|
|
331
|
-
layoutMode: state.layout.layoutMode,
|
|
332
|
-
navigationPadEnabled: state.layout.navigationPadEnabled,
|
|
333
|
-
};
|
|
334
|
-
};
|
|
335
|
-
|
|
336
|
-
const mapDispatchToProps = (dispatch) => {
|
|
337
|
-
return {
|
|
338
|
-
onPageSizeChange: (
|
|
339
|
-
pageWidth: number,
|
|
340
|
-
pageHeight: number,
|
|
341
|
-
containerWidth: number,
|
|
342
|
-
containerHeight: number,
|
|
343
|
-
) => {
|
|
344
|
-
dispatch(
|
|
345
|
-
setPageSize(
|
|
346
|
-
pageWidth,
|
|
347
|
-
pageHeight,
|
|
348
|
-
containerWidth,
|
|
349
|
-
containerHeight,
|
|
350
|
-
),
|
|
351
|
-
);
|
|
352
|
-
},
|
|
353
|
-
};
|
|
354
|
-
};
|
|
355
|
-
|
|
356
|
-
export default connect(mapStateToProps, mapDispatchToProps, null, {
|
|
357
|
-
forwardRef: true,
|
|
358
|
-
})(KeypadContainer);
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A keypad component that acts as a container for rows or columns of buttons,
|
|
3
|
-
* and manages the rendering of echo animations on top of those buttons.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import * as React from "react";
|
|
7
|
-
import ReactDOM from "react-dom";
|
|
8
|
-
import {connect} from "react-redux";
|
|
9
|
-
|
|
10
|
-
import {View} from "../../fake-react-native-web/index";
|
|
11
|
-
|
|
12
|
-
import EchoManager from "./echo-manager";
|
|
13
|
-
import PopoverManager from "./popover-manager";
|
|
14
|
-
import {removeEcho} from "./store/actions";
|
|
15
|
-
|
|
16
|
-
import type {Bound, Popover, Echo} from "../../types";
|
|
17
|
-
import type {State} from "./store/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
|
-
}
|
|
31
|
-
|
|
32
|
-
// eslint-disable-next-line react/no-unsafe
|
|
33
|
-
class Keypad extends React.Component<Props> {
|
|
34
|
-
_isMounted: boolean | undefined;
|
|
35
|
-
_resizeTimeout: number | null | undefined;
|
|
36
|
-
_container: Bound | null | undefined;
|
|
37
|
-
|
|
38
|
-
componentDidMount() {
|
|
39
|
-
this._isMounted = true;
|
|
40
|
-
|
|
41
|
-
window.addEventListener("resize", this._onResize);
|
|
42
|
-
this._updateSizeAndPosition();
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
UNSAFE_componentWillReceiveProps(newProps) {
|
|
46
|
-
if (!this._container && (newProps.popover || newProps.echoes.length)) {
|
|
47
|
-
this._computeContainer();
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
componentWillUnmount() {
|
|
52
|
-
this._isMounted = false;
|
|
53
|
-
|
|
54
|
-
window.removeEventListener("resize", this._onResize);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
_computeContainer = () => {
|
|
58
|
-
const domNode = ReactDOM.findDOMNode(this) as Element;
|
|
59
|
-
this._container = domNode.getBoundingClientRect();
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
_updateSizeAndPosition = () => {
|
|
63
|
-
// Mark the container for recalculation next time the keypad is
|
|
64
|
-
// opened.
|
|
65
|
-
// TODO(charlie): Since we're not recalculating the container
|
|
66
|
-
// immediately, if you were to resize the page while a popover were
|
|
67
|
-
// active, you'd likely get unexpected behavior. This seems very
|
|
68
|
-
// difficult to do and, as such, incredibly unlikely, but we may
|
|
69
|
-
// want to reconsider the caching here.
|
|
70
|
-
this._container = null;
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
_onResize = () => {
|
|
74
|
-
// Whenever the page resizes, we need to recompute the container's
|
|
75
|
-
// bounding box. This is the only time that the bounding box can change.
|
|
76
|
-
|
|
77
|
-
// Throttle resize events -- taken from:
|
|
78
|
-
// https://developer.mozilla.org/en-US/docs/Web/Events/resize
|
|
79
|
-
if (this._resizeTimeout == null) {
|
|
80
|
-
this._resizeTimeout = window.setTimeout(() => {
|
|
81
|
-
this._resizeTimeout = null;
|
|
82
|
-
|
|
83
|
-
if (this._isMounted) {
|
|
84
|
-
this._updateSizeAndPosition();
|
|
85
|
-
}
|
|
86
|
-
}, 66);
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
render() {
|
|
91
|
-
const {children, echoes, removeEcho, popover, style} = this.props;
|
|
92
|
-
|
|
93
|
-
// Translate the echo boxes, as they'll be positioned absolutely to
|
|
94
|
-
// this relative container.
|
|
95
|
-
const relativeEchoes = echoes.map((echo) => {
|
|
96
|
-
const {initialBounds, ...rest} = echo;
|
|
97
|
-
return {
|
|
98
|
-
...rest,
|
|
99
|
-
initialBounds: {
|
|
100
|
-
// @ts-expect-error TS2533
|
|
101
|
-
top: initialBounds.top - this._container.top,
|
|
102
|
-
// @ts-expect-error TS2533
|
|
103
|
-
right: initialBounds.right - this._container.left,
|
|
104
|
-
// @ts-expect-error TS2533
|
|
105
|
-
bottom: initialBounds.bottom - this._container.top,
|
|
106
|
-
// @ts-expect-error TS2533
|
|
107
|
-
left: initialBounds.left - this._container.left,
|
|
108
|
-
width: initialBounds.width,
|
|
109
|
-
height: initialBounds.height,
|
|
110
|
-
},
|
|
111
|
-
};
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
// Translate the popover bounds from page-absolute to keypad-relative.
|
|
115
|
-
// Note that we only need three bounds, since popovers are anchored to
|
|
116
|
-
// the bottom left corners of the keys over which they appear.
|
|
117
|
-
const relativePopover = popover && {
|
|
118
|
-
...popover,
|
|
119
|
-
bounds: {
|
|
120
|
-
bottom:
|
|
121
|
-
// @ts-expect-error TS2533
|
|
122
|
-
this._container.height -
|
|
123
|
-
// @ts-expect-error TS2533
|
|
124
|
-
(popover.bounds.bottom - this._container.top),
|
|
125
|
-
// @ts-expect-error TS2533
|
|
126
|
-
left: popover.bounds.left - this._container.left,
|
|
127
|
-
width: popover.bounds.width,
|
|
128
|
-
},
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
return (
|
|
132
|
-
<View style={style}>
|
|
133
|
-
{children}
|
|
134
|
-
<EchoManager
|
|
135
|
-
echoes={relativeEchoes}
|
|
136
|
-
onAnimationFinish={removeEcho}
|
|
137
|
-
/>
|
|
138
|
-
<PopoverManager popover={relativePopover} />
|
|
139
|
-
</View>
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const mapStateToProps = (state: State): ReduxProps => {
|
|
145
|
-
return {
|
|
146
|
-
echoes: state.echoes.echoes,
|
|
147
|
-
active: state.keypad.active,
|
|
148
|
-
popover: state.gestures.popover,
|
|
149
|
-
};
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
const mapDispatchToProps = (dispatch) => {
|
|
153
|
-
return {
|
|
154
|
-
removeEcho: (animationId) => {
|
|
155
|
-
dispatch(removeEcho(animationId));
|
|
156
|
-
},
|
|
157
|
-
};
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
export default connect(mapStateToProps, mapDispatchToProps, null, {
|
|
161
|
-
forwardRef: true,
|
|
162
|
-
})(Keypad);
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A keypad button that displays an arbitrary number of symbols, with no
|
|
3
|
-
* 'default' symbol.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import * as React from "react";
|
|
7
|
-
|
|
8
|
-
import KeyConfigs from "../../data/key-configs";
|
|
9
|
-
import {IconType} from "../../enums";
|
|
10
|
-
|
|
11
|
-
import EmptyKeypadButton from "./empty-keypad-button";
|
|
12
|
-
import TouchableKeypadButton from "./touchable-keypad-button";
|
|
13
|
-
|
|
14
|
-
import type {KeyConfig} from "../../types";
|
|
15
|
-
|
|
16
|
-
type Props = {
|
|
17
|
-
keys: ReadonlyArray<string>;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
class ManyKeypadButton extends React.Component<Props> {
|
|
21
|
-
static defaultProps = {
|
|
22
|
-
keys: [],
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
render() {
|
|
26
|
-
const {keys, ...rest} = this.props;
|
|
27
|
-
|
|
28
|
-
// If we have no extra symbols, render an empty button. If we have just
|
|
29
|
-
// one, render a standard button. Otherwise, capture them all in a
|
|
30
|
-
// single button.
|
|
31
|
-
if (keys.length === 0) {
|
|
32
|
-
return <EmptyKeypadButton />;
|
|
33
|
-
} else if (keys.length === 1) {
|
|
34
|
-
const keyConfig = KeyConfigs[keys[0]];
|
|
35
|
-
return <TouchableKeypadButton keyConfig={keyConfig} {...rest} />;
|
|
36
|
-
} else {
|
|
37
|
-
const keyConfig: KeyConfig = {
|
|
38
|
-
id: "MANY",
|
|
39
|
-
type: "MANY",
|
|
40
|
-
childKeyIds: keys,
|
|
41
|
-
ariaLabel: keys
|
|
42
|
-
.map((key) => KeyConfigs[key].ariaLabel)
|
|
43
|
-
.join(", "),
|
|
44
|
-
icon: {
|
|
45
|
-
type: IconType.SVG,
|
|
46
|
-
data: "many",
|
|
47
|
-
},
|
|
48
|
-
};
|
|
49
|
-
return <TouchableKeypadButton keyConfig={keyConfig} {...rest} />;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export default ManyKeypadButton;
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A component that renders an icon with math (via KaTeX).
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import {StyleSheet} from "aphrodite";
|
|
6
|
-
import katex from "katex";
|
|
7
|
-
import * as React from "react";
|
|
8
|
-
import ReactDOM from "react-dom";
|
|
9
|
-
|
|
10
|
-
import {View} from "../../fake-react-native-web/index";
|
|
11
|
-
import {iconSizeHeightPx, iconSizeWidthPx} from "../common-style";
|
|
12
|
-
|
|
13
|
-
import Styles from "./styles";
|
|
14
|
-
|
|
15
|
-
import type {StyleType} from "@khanacademy/wonder-blocks-core";
|
|
16
|
-
|
|
17
|
-
const {row, centered} = Styles;
|
|
18
|
-
|
|
19
|
-
type Props = {
|
|
20
|
-
math: string;
|
|
21
|
-
style: StyleType;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
class MathIcon extends React.Component<Props> {
|
|
25
|
-
componentDidMount() {
|
|
26
|
-
this._renderMath();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
componentDidUpdate(prevProps) {
|
|
30
|
-
if (prevProps.math !== this.props.math) {
|
|
31
|
-
this._renderMath();
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
_renderMath = () => {
|
|
36
|
-
const {math} = this.props;
|
|
37
|
-
katex.render(math, ReactDOM.findDOMNode(this));
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
render() {
|
|
41
|
-
const {style} = this.props;
|
|
42
|
-
|
|
43
|
-
const containerStyle = [
|
|
44
|
-
row,
|
|
45
|
-
centered,
|
|
46
|
-
styles.size,
|
|
47
|
-
styles.base,
|
|
48
|
-
...(Array.isArray(style) ? style : [style]),
|
|
49
|
-
];
|
|
50
|
-
|
|
51
|
-
return <View style={containerStyle} />;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const styles = StyleSheet.create({
|
|
56
|
-
size: {
|
|
57
|
-
height: iconSizeHeightPx,
|
|
58
|
-
width: iconSizeWidthPx,
|
|
59
|
-
},
|
|
60
|
-
|
|
61
|
-
base: {
|
|
62
|
-
fontSize: 25,
|
|
63
|
-
},
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
export default MathIcon;
|