@khanacademy/math-input 13.1.0 → 14.0.1
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 +17 -0
- package/dist/components/keypad/mobile-keypad.d.ts +2 -1
- package/dist/components/keypad-context.d.ts +10 -16
- package/dist/components/keypad-legacy/provided-keypad.d.ts +5 -0
- package/dist/es/index.js +112 -77
- package/dist/es/index.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +115 -77
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +11 -0
- package/dist/version.d.ts +1 -0
- package/package.json +3 -3
- package/src/components/__tests__/integration.test.tsx +4 -18
- package/src/components/keypad/__tests__/__snapshots__/keypad.test.tsx.snap +0 -2
- package/src/components/keypad/keypad.tsx +0 -1
- package/src/components/keypad/mobile-keypad.tsx +10 -12
- package/src/components/keypad-context.tsx +61 -0
- package/src/components/keypad-legacy/provided-keypad.tsx +50 -34
- package/src/components/keypad-switch.tsx +14 -1
- package/src/full-mobile-input.stories.tsx +23 -20
- package/src/index.ts +6 -1
- package/src/types.ts +16 -0
- package/src/version.ts +10 -0
- package/tsconfig-build.json +1 -0
- package/tsconfig-build.tsbuildinfo +1 -1
- package/src/components/keypad-context.ts +0 -37
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CursorContext } from "./components/input/cursor-contexts";
|
|
2
2
|
import type Key from "./data/keys";
|
|
3
3
|
import type { BorderDirection, EchoAnimationType, IconType, KeyType, KeypadType } from "./enums";
|
|
4
|
+
import type { KeypadContextRendererInterface } from "@khanacademy/perseus-core";
|
|
4
5
|
import type * as React from "react";
|
|
5
6
|
import type ReactDOM from "react-dom";
|
|
6
7
|
export type Border = Partial<ReadonlyArray<BorderDirection>>;
|
|
@@ -74,4 +75,14 @@ export interface KeypadAPI {
|
|
|
74
75
|
setKeyHandler: (keyHandler: KeyHandler) => void;
|
|
75
76
|
getDOMNode: () => ReturnType<typeof ReactDOM.findDOMNode>;
|
|
76
77
|
}
|
|
78
|
+
export type KeypadContextType = {
|
|
79
|
+
setKeypadActive: (keypadActive: boolean) => void;
|
|
80
|
+
keypadActive: boolean;
|
|
81
|
+
setKeypadElement: (keypadElement?: KeypadAPI) => void;
|
|
82
|
+
keypadElement: KeypadAPI | null | undefined;
|
|
83
|
+
setRenderer: (renderer?: KeypadContextRendererInterface | null | undefined) => void;
|
|
84
|
+
renderer: KeypadContextRendererInterface | null | undefined;
|
|
85
|
+
setScrollableElement: (scrollableElement?: HTMLElement | null | undefined) => void;
|
|
86
|
+
scrollableElement: HTMLElement | null | undefined;
|
|
87
|
+
};
|
|
77
88
|
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const libVersion = "__lib_version__";
|
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": "
|
|
6
|
+
"version": "14.0.1",
|
|
7
7
|
"publishConfig": {
|
|
8
8
|
"access": "public"
|
|
9
9
|
},
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"source": "src/index.ts",
|
|
21
21
|
"scripts": {},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@khanacademy/perseus-core": "1.1.
|
|
23
|
+
"@khanacademy/perseus-core": "1.1.1",
|
|
24
24
|
"mathquill": "git+https://git@github.com/Khan/mathquill.git#32d9f351aaa68537170b3120a52e99b8def3a2c3",
|
|
25
25
|
"performance-now": "^0.2.0"
|
|
26
26
|
},
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"aphrodite": "^1.1.0",
|
|
35
35
|
"jquery": "^2.1.1",
|
|
36
36
|
"katex": "^0.11.1",
|
|
37
|
-
"perseus-build-settings": "^0.2.
|
|
37
|
+
"perseus-build-settings": "^0.2.1",
|
|
38
38
|
"prop-types": "15.6.1",
|
|
39
39
|
"react": "^16.8.0",
|
|
40
40
|
"react-dom": "^16.8.0",
|
|
@@ -12,10 +12,10 @@ import React, {useState} from "react";
|
|
|
12
12
|
|
|
13
13
|
import {KeypadType} from "../../enums";
|
|
14
14
|
import MathInput from "../input/math-input";
|
|
15
|
-
import KeypadContext from "../keypad-context";
|
|
15
|
+
import {KeypadContext, StatefulKeypadContextProvider} from "../keypad-context";
|
|
16
16
|
import KeypadSwitch from "../keypad-switch";
|
|
17
17
|
|
|
18
|
-
import type {
|
|
18
|
+
import type {KeypadConfiguration} from "../../types";
|
|
19
19
|
|
|
20
20
|
const MQ = MathQuill.getInterface(2);
|
|
21
21
|
|
|
@@ -73,25 +73,11 @@ function KeypadWithContext() {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
function ConnectedMathInput({keypadConfiguration = defaultConfiguration}) {
|
|
76
|
-
const [keypadElement, setKeypadElement] = useState<KeypadAPI | null>();
|
|
77
|
-
const [renderer, setRenderer] = useState<any>(null);
|
|
78
|
-
const [scrollableElement, setScrollableElement] =
|
|
79
|
-
useState<HTMLElement | null>();
|
|
80
|
-
|
|
81
76
|
return (
|
|
82
|
-
<
|
|
83
|
-
value={{
|
|
84
|
-
setKeypadElement,
|
|
85
|
-
keypadElement,
|
|
86
|
-
setRenderer,
|
|
87
|
-
renderer,
|
|
88
|
-
setScrollableElement,
|
|
89
|
-
scrollableElement,
|
|
90
|
-
}}
|
|
91
|
-
>
|
|
77
|
+
<StatefulKeypadContextProvider>
|
|
92
78
|
<InputWithContext keypadConfiguration={keypadConfiguration} />
|
|
93
79
|
<KeypadWithContext />
|
|
94
|
-
</
|
|
80
|
+
</StatefulKeypadContextProvider>
|
|
95
81
|
);
|
|
96
82
|
}
|
|
97
83
|
|
|
@@ -170,7 +170,6 @@ exports[`keypad should snapshot expanded: first render 1`] = `
|
|
|
170
170
|
<div
|
|
171
171
|
aria-label="Keypad"
|
|
172
172
|
class="default_xu2jcg-o_O-keypadGrid_ztxlrb-o_O-expressionGrid_1fuqhx9"
|
|
173
|
-
role="grid"
|
|
174
173
|
tabindex="0"
|
|
175
174
|
>
|
|
176
175
|
<div
|
|
@@ -1223,7 +1222,6 @@ exports[`keypad should snapshot unexpanded: first render 1`] = `
|
|
|
1223
1222
|
<div
|
|
1224
1223
|
aria-label="Keypad"
|
|
1225
1224
|
class="default_xu2jcg-o_O-keypadGrid_ztxlrb-o_O-expressionGrid_1fuqhx9"
|
|
1226
|
-
role="grid"
|
|
1227
1225
|
tabindex="0"
|
|
1228
1226
|
>
|
|
1229
1227
|
<div
|
|
@@ -4,6 +4,7 @@ import ReactDOM from "react-dom";
|
|
|
4
4
|
|
|
5
5
|
import {View} from "../../fake-react-native-web/index";
|
|
6
6
|
|
|
7
|
+
import Keypad from "./keypad";
|
|
7
8
|
import {expandedViewThreshold} from "./utils";
|
|
8
9
|
|
|
9
10
|
import type Key from "../../data/keys";
|
|
@@ -16,8 +17,6 @@ import type {
|
|
|
16
17
|
import type {AnalyticsEventHandlerFn} from "@khanacademy/perseus-core";
|
|
17
18
|
import type {StyleType} from "@khanacademy/wonder-blocks-core";
|
|
18
19
|
|
|
19
|
-
import Keypad from "./index";
|
|
20
|
-
|
|
21
20
|
/**
|
|
22
21
|
* This is the v2 equivalent of v1's ProvidedKeypad. It follows the same
|
|
23
22
|
* external API so that it can be hot-swapped with the v1 keypad and
|
|
@@ -34,10 +33,11 @@ type Props = {
|
|
|
34
33
|
onDismiss?: () => void;
|
|
35
34
|
style?: StyleType;
|
|
36
35
|
onAnalyticsEvent: AnalyticsEventHandlerFn;
|
|
36
|
+
setKeypadActive: (keypadActive: boolean) => void;
|
|
37
|
+
keypadActive: boolean;
|
|
37
38
|
};
|
|
38
39
|
|
|
39
40
|
type State = {
|
|
40
|
-
active: boolean;
|
|
41
41
|
containerWidth: number;
|
|
42
42
|
hasBeenActivated: boolean;
|
|
43
43
|
keypadConfig?: KeypadConfiguration;
|
|
@@ -52,7 +52,6 @@ class MobileKeypad extends React.Component<Props, State> implements KeypadAPI {
|
|
|
52
52
|
hasMounted = false;
|
|
53
53
|
|
|
54
54
|
state: State = {
|
|
55
|
-
active: false,
|
|
56
55
|
containerWidth: 0,
|
|
57
56
|
hasBeenActivated: false,
|
|
58
57
|
};
|
|
@@ -109,16 +108,15 @@ class MobileKeypad extends React.Component<Props, State> implements KeypadAPI {
|
|
|
109
108
|
};
|
|
110
109
|
|
|
111
110
|
activate: () => void = () => {
|
|
111
|
+
this.props.setKeypadActive(true);
|
|
112
112
|
this.setState({
|
|
113
|
-
active: true,
|
|
114
113
|
hasBeenActivated: true,
|
|
115
114
|
});
|
|
116
115
|
};
|
|
117
116
|
|
|
118
117
|
dismiss: () => void = () => {
|
|
119
|
-
this.
|
|
120
|
-
|
|
121
|
-
});
|
|
118
|
+
this.props.setKeypadActive(false);
|
|
119
|
+
this.props.onDismiss?.();
|
|
122
120
|
};
|
|
123
121
|
|
|
124
122
|
configure: (configuration: KeypadConfiguration, cb: () => void) => void = (
|
|
@@ -162,14 +160,14 @@ class MobileKeypad extends React.Component<Props, State> implements KeypadAPI {
|
|
|
162
160
|
}
|
|
163
161
|
|
|
164
162
|
render(): React.ReactNode {
|
|
165
|
-
const {style} = this.props;
|
|
166
|
-
const {
|
|
163
|
+
const {keypadActive, style} = this.props;
|
|
164
|
+
const {hasBeenActivated, containerWidth, cursor, keypadConfig} =
|
|
167
165
|
this.state;
|
|
168
166
|
|
|
169
167
|
const containerStyle = [
|
|
170
168
|
// internal styles
|
|
171
169
|
styles.keypadContainer,
|
|
172
|
-
|
|
170
|
+
keypadActive && styles.activeKeypadContainer,
|
|
173
171
|
// styles passed as props
|
|
174
172
|
...(Array.isArray(style) ? style : [style]),
|
|
175
173
|
];
|
|
@@ -179,7 +177,7 @@ class MobileKeypad extends React.Component<Props, State> implements KeypadAPI {
|
|
|
179
177
|
// during the initial render.
|
|
180
178
|
// Done inline (dynamicStyle) since stylesheets might not be loaded yet.
|
|
181
179
|
let dynamicStyle = {};
|
|
182
|
-
if (!
|
|
180
|
+
if (!keypadActive && !hasBeenActivated) {
|
|
183
181
|
dynamicStyle = {visibility: "hidden"};
|
|
184
182
|
}
|
|
185
183
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KeypadContext provides a way to the Keypad and Perseus Renderers to
|
|
3
|
+
* communicate.
|
|
4
|
+
*
|
|
5
|
+
* The StatefulKeypadContextProvider wraps the application
|
|
6
|
+
* while KeypadContext.Consumer wraps things that need this state:
|
|
7
|
+
* - mobile keypad usages
|
|
8
|
+
* - Perseus Renderers (Server/Item/Article)
|
|
9
|
+
*/
|
|
10
|
+
import * as React from "react";
|
|
11
|
+
import {useState} from "react";
|
|
12
|
+
|
|
13
|
+
import type {KeypadAPI, KeypadContextType} from "../types";
|
|
14
|
+
import type {KeypadContextRendererInterface} from "@khanacademy/perseus-core";
|
|
15
|
+
|
|
16
|
+
// @ts-expect-error - TS2322 - Type 'Context<{ setKeypadElement: (keypadElement: HTMLElement | null | undefined) => void; keypadElement: null; setRenderer: (renderer: RendererInterface | null | undefined) => void; renderer: null; setScrollableElement: (scrollableElement: HTMLElement | ... 1 more ... | undefined) => void; scrollableElement: null; }>' is not assignable to type 'Context<KeypadContext>'.
|
|
17
|
+
export const KeypadContext: React.Context<KeypadContextType> =
|
|
18
|
+
React.createContext({
|
|
19
|
+
setKeypadActive: (keypadActive) => {},
|
|
20
|
+
keypadActive: false,
|
|
21
|
+
setKeypadElement: (keypadElement) => {},
|
|
22
|
+
keypadElement: null,
|
|
23
|
+
setRenderer: (renderer) => {},
|
|
24
|
+
renderer: null,
|
|
25
|
+
setScrollableElement: (scrollableElement) => {},
|
|
26
|
+
scrollableElement: null,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
type Props = React.PropsWithChildren<unknown>;
|
|
30
|
+
|
|
31
|
+
export function StatefulKeypadContextProvider(props: Props) {
|
|
32
|
+
// whether or not to display the keypad
|
|
33
|
+
const [keypadActive, setKeypadActive] = useState<boolean>(false);
|
|
34
|
+
// used to communicate between the keypad and the Renderer
|
|
35
|
+
const [keypadElement, setKeypadElement] = useState<KeypadAPI | null>();
|
|
36
|
+
// this is a KeypadContextRendererInterface from Perseus
|
|
37
|
+
const [renderer, setRenderer] =
|
|
38
|
+
useState<KeypadContextRendererInterface | null>();
|
|
39
|
+
const [scrollableElement, setScrollableElement] =
|
|
40
|
+
useState<HTMLElement | null>();
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<KeypadContext.Provider
|
|
44
|
+
value={{
|
|
45
|
+
setKeypadActive,
|
|
46
|
+
keypadActive,
|
|
47
|
+
setKeypadElement,
|
|
48
|
+
keypadElement,
|
|
49
|
+
setRenderer,
|
|
50
|
+
renderer,
|
|
51
|
+
// The scrollableElement options can likely be removed after
|
|
52
|
+
// the exercises-package is officially deprecated. They don't appear
|
|
53
|
+
// to be used anywhere except for the exercises-package and tests.
|
|
54
|
+
setScrollableElement,
|
|
55
|
+
scrollableElement,
|
|
56
|
+
}}
|
|
57
|
+
>
|
|
58
|
+
{props.children}
|
|
59
|
+
</KeypadContext.Provider>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
@@ -22,6 +22,8 @@ import type {AnalyticsEventHandlerFn} from "@khanacademy/perseus-core";
|
|
|
22
22
|
import type {StyleType} from "@khanacademy/wonder-blocks-core";
|
|
23
23
|
|
|
24
24
|
type Props = {
|
|
25
|
+
setKeypadActive: (keypadActive: boolean) => void;
|
|
26
|
+
keypadActive: boolean;
|
|
25
27
|
onElementMounted?: (arg1: any) => void;
|
|
26
28
|
onDismiss?: () => void;
|
|
27
29
|
style?: StyleType;
|
|
@@ -37,12 +39,22 @@ class ProvidedKeypad extends React.Component<Props> implements KeypadAPI {
|
|
|
37
39
|
this.store = createStore();
|
|
38
40
|
}
|
|
39
41
|
|
|
42
|
+
componentDidUpdate(prevProps) {
|
|
43
|
+
if (this.props.keypadActive && !prevProps.keypadActive) {
|
|
44
|
+
this.store.dispatch(activateKeypad());
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!this.props.keypadActive && prevProps.keypadActive) {
|
|
48
|
+
this.store.dispatch(dismissKeypad());
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
40
52
|
activate: () => void = () => {
|
|
41
|
-
this.
|
|
53
|
+
this.props.setKeypadActive(true);
|
|
42
54
|
};
|
|
43
55
|
|
|
44
56
|
dismiss: () => void = () => {
|
|
45
|
-
this.
|
|
57
|
+
this.props.setKeypadActive(false);
|
|
46
58
|
};
|
|
47
59
|
|
|
48
60
|
configure: (configuration: KeypadConfiguration, cb: () => void) => void = (
|
|
@@ -73,43 +85,47 @@ class ProvidedKeypad extends React.Component<Props> implements KeypadAPI {
|
|
|
73
85
|
return ReactDOM.findDOMNode(this);
|
|
74
86
|
};
|
|
75
87
|
|
|
88
|
+
onElementMounted: (element: any) => void = (element) => {
|
|
89
|
+
this.props.onAnalyticsEvent({
|
|
90
|
+
type: "math-input:keypad-opened",
|
|
91
|
+
payload: {
|
|
92
|
+
virtualKeypadVersion: "MATH_INPUT_KEYPAD_V1",
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Append the dispatch methods that we want to expose
|
|
97
|
+
// externally to the returned React element.
|
|
98
|
+
const elementWithDispatchMethods = {
|
|
99
|
+
...element,
|
|
100
|
+
activate: this.activate,
|
|
101
|
+
dismiss: this.dismiss,
|
|
102
|
+
configure: this.configure,
|
|
103
|
+
setCursor: this.setCursor,
|
|
104
|
+
setKeyHandler: this.setKeyHandler,
|
|
105
|
+
getDOMNode: this.getDOMNode,
|
|
106
|
+
} as const;
|
|
107
|
+
this.props.onElementMounted?.(elementWithDispatchMethods);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
onDismiss: () => void = () => {
|
|
111
|
+
this.props.onAnalyticsEvent({
|
|
112
|
+
type: "math-input:keypad-closed",
|
|
113
|
+
payload: {
|
|
114
|
+
virtualKeypadVersion: "MATH_INPUT_KEYPAD_V1",
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
this.props.onDismiss?.();
|
|
119
|
+
};
|
|
120
|
+
|
|
76
121
|
render(): React.ReactNode {
|
|
77
|
-
const {
|
|
122
|
+
const {style} = this.props;
|
|
78
123
|
|
|
79
124
|
return (
|
|
80
125
|
<Provider store={this.store}>
|
|
81
126
|
<KeypadContainer
|
|
82
|
-
onElementMounted={
|
|
83
|
-
|
|
84
|
-
type: "math-input:keypad-opened",
|
|
85
|
-
payload: {
|
|
86
|
-
virtualKeypadVersion: "MATH_INPUT_KEYPAD_V1",
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
// Append the dispatch methods that we want to expose
|
|
91
|
-
// externally to the returned React element.
|
|
92
|
-
const elementWithDispatchMethods = {
|
|
93
|
-
...element,
|
|
94
|
-
activate: this.activate,
|
|
95
|
-
dismiss: this.dismiss,
|
|
96
|
-
configure: this.configure,
|
|
97
|
-
setCursor: this.setCursor,
|
|
98
|
-
setKeyHandler: this.setKeyHandler,
|
|
99
|
-
getDOMNode: this.getDOMNode,
|
|
100
|
-
} as const;
|
|
101
|
-
onElementMounted?.(elementWithDispatchMethods);
|
|
102
|
-
}}
|
|
103
|
-
onDismiss={() => {
|
|
104
|
-
this.props.onAnalyticsEvent({
|
|
105
|
-
type: "math-input:keypad-closed",
|
|
106
|
-
payload: {
|
|
107
|
-
virtualKeypadVersion: "MATH_INPUT_KEYPAD_V1",
|
|
108
|
-
},
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
onDismiss?.();
|
|
112
|
-
}}
|
|
127
|
+
onElementMounted={this.onElementMounted}
|
|
128
|
+
onDismiss={this.onDismiss}
|
|
113
129
|
style={style}
|
|
114
130
|
/>
|
|
115
131
|
</Provider>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
3
|
import {MobileKeypad} from "./keypad";
|
|
4
|
+
import {KeypadContext} from "./keypad-context";
|
|
4
5
|
import LegacyKeypad from "./keypad-legacy";
|
|
5
6
|
|
|
6
7
|
import type {AnalyticsEventHandlerFn} from "@khanacademy/perseus-core";
|
|
@@ -23,7 +24,19 @@ function KeypadSwitch(props: Props) {
|
|
|
23
24
|
// Note: Although we pass the "onAnalyticsEvent" to both keypad components,
|
|
24
25
|
// only the current one uses it. There's no point in instrumenting the
|
|
25
26
|
// legacy keypad given that it's on its way out the door.
|
|
26
|
-
return
|
|
27
|
+
return (
|
|
28
|
+
<KeypadContext.Consumer>
|
|
29
|
+
{({setKeypadActive, keypadActive}) => {
|
|
30
|
+
return (
|
|
31
|
+
<KeypadComponent
|
|
32
|
+
{...rest}
|
|
33
|
+
keypadActive={keypadActive}
|
|
34
|
+
setKeypadActive={setKeypadActive}
|
|
35
|
+
/>
|
|
36
|
+
);
|
|
37
|
+
}}
|
|
38
|
+
</KeypadContext.Consumer>
|
|
39
|
+
);
|
|
27
40
|
}
|
|
28
41
|
|
|
29
42
|
export default KeypadSwitch;
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import {action} from "@storybook/addon-actions";
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import {
|
|
5
|
+
KeypadInput,
|
|
6
|
+
KeypadType,
|
|
7
|
+
MobileKeypad,
|
|
8
|
+
StatefulKeypadContextProvider,
|
|
9
|
+
KeypadContext,
|
|
10
|
+
} from "./index";
|
|
7
11
|
|
|
8
12
|
export default {
|
|
9
13
|
title: "math-input/Full Mobile MathInput",
|
|
@@ -19,32 +23,19 @@ export default {
|
|
|
19
23
|
},
|
|
20
24
|
};
|
|
21
25
|
|
|
22
|
-
|
|
26
|
+
const Basic = ({keypadElement, setKeypadElement}) => {
|
|
23
27
|
const [value, setValue] = React.useState("");
|
|
24
|
-
// Reference to the keypad
|
|
25
|
-
const [keypadElement, setKeypadElement] = React.useState<KeypadAPI>();
|
|
26
28
|
// Whether to use Expression or Fraction keypad
|
|
27
29
|
const [expression, setExpression] = React.useState<boolean>(false);
|
|
28
30
|
// Whether to use CDOT or TIMES
|
|
29
31
|
const [times, setTimes] = React.useState<boolean>(true);
|
|
30
32
|
// Whether to use v1 or v2 keypad
|
|
31
33
|
const [v2Keypad, setV2Keypad] = React.useState<boolean>(true);
|
|
32
|
-
// Whether the keypad is open or not
|
|
33
|
-
const [keypadOpen, setKeypadOpen] = React.useState<boolean>(false);
|
|
34
34
|
|
|
35
35
|
const input = React.useRef<KeypadInput>(null);
|
|
36
36
|
|
|
37
37
|
const timesLabel = times ? "CDOT" : "TIMES";
|
|
38
38
|
|
|
39
|
-
const toggleKeypad = () => {
|
|
40
|
-
if (keypadOpen) {
|
|
41
|
-
keypadElement?.dismiss();
|
|
42
|
-
} else {
|
|
43
|
-
keypadElement?.activate();
|
|
44
|
-
}
|
|
45
|
-
setKeypadOpen(!keypadOpen);
|
|
46
|
-
};
|
|
47
|
-
|
|
48
39
|
React.useEffect(() => {
|
|
49
40
|
keypadElement?.configure(
|
|
50
41
|
{
|
|
@@ -73,9 +64,6 @@ export const Basic = () => {
|
|
|
73
64
|
<button onClick={() => setV2Keypad(!v2Keypad)}>
|
|
74
65
|
{`Use ${v2Keypad ? "Legacy" : "New"} Keypad`}
|
|
75
66
|
</button>
|
|
76
|
-
<button onClick={() => toggleKeypad()}>
|
|
77
|
-
{`Toggle Keypad`}
|
|
78
|
-
</button>
|
|
79
67
|
<button onClick={() => setTimes(!times)}>
|
|
80
68
|
{`Toggle to ` + timesLabel}
|
|
81
69
|
</button>
|
|
@@ -111,3 +99,18 @@ export const Basic = () => {
|
|
|
111
99
|
</div>
|
|
112
100
|
);
|
|
113
101
|
};
|
|
102
|
+
|
|
103
|
+
export function Wrapped() {
|
|
104
|
+
return (
|
|
105
|
+
<StatefulKeypadContextProvider>
|
|
106
|
+
<KeypadContext.Consumer>
|
|
107
|
+
{({keypadElement, setKeypadElement}) => (
|
|
108
|
+
<Basic
|
|
109
|
+
keypadElement={keypadElement}
|
|
110
|
+
setKeypadElement={setKeypadElement}
|
|
111
|
+
/>
|
|
112
|
+
)}
|
|
113
|
+
</KeypadContext.Consumer>
|
|
114
|
+
</StatefulKeypadContextProvider>
|
|
115
|
+
);
|
|
116
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
import "../less/main.less";
|
|
6
6
|
|
|
7
|
+
export {libVersion} from "./version";
|
|
8
|
+
|
|
7
9
|
// MathInput input field (MathQuill wrapper)
|
|
8
10
|
export {default as KeypadInput} from "./components/input/math-input";
|
|
9
11
|
|
|
@@ -30,7 +32,10 @@ export {default as MobileKeypad} from "./components/keypad-switch";
|
|
|
30
32
|
export {default as DesktopKeypad} from "./components/keypad";
|
|
31
33
|
|
|
32
34
|
// Context used to pass data/refs around
|
|
33
|
-
export {
|
|
35
|
+
export {
|
|
36
|
+
KeypadContext,
|
|
37
|
+
StatefulKeypadContextProvider,
|
|
38
|
+
} from "./components/keypad-context";
|
|
34
39
|
|
|
35
40
|
// External API of the "Provided" keypad component
|
|
36
41
|
export {keypadElementPropType} from "./components/prop-types";
|
package/src/types.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
KeyType,
|
|
8
8
|
KeypadType,
|
|
9
9
|
} from "./enums";
|
|
10
|
+
import type {KeypadContextRendererInterface} from "@khanacademy/perseus-core";
|
|
10
11
|
import type * as React from "react";
|
|
11
12
|
import type ReactDOM from "react-dom";
|
|
12
13
|
|
|
@@ -105,3 +106,18 @@ export interface KeypadAPI {
|
|
|
105
106
|
setKeyHandler: (keyHandler: KeyHandler) => void;
|
|
106
107
|
getDOMNode: () => ReturnType<typeof ReactDOM.findDOMNode>;
|
|
107
108
|
}
|
|
109
|
+
|
|
110
|
+
export type KeypadContextType = {
|
|
111
|
+
setKeypadActive: (keypadActive: boolean) => void;
|
|
112
|
+
keypadActive: boolean;
|
|
113
|
+
setKeypadElement: (keypadElement?: KeypadAPI) => void;
|
|
114
|
+
keypadElement: KeypadAPI | null | undefined;
|
|
115
|
+
setRenderer: (
|
|
116
|
+
renderer?: KeypadContextRendererInterface | null | undefined,
|
|
117
|
+
) => void;
|
|
118
|
+
renderer: KeypadContextRendererInterface | null | undefined;
|
|
119
|
+
setScrollableElement: (
|
|
120
|
+
scrollableElement?: HTMLElement | null | undefined,
|
|
121
|
+
) => void;
|
|
122
|
+
scrollableElement: HTMLElement | null | undefined;
|
|
123
|
+
};
|
package/src/version.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
2
|
+
// version number during the release build.
|
|
3
|
+
// In dev, you'll never see the version number.
|
|
4
|
+
|
|
5
|
+
import {addLibraryVersionToPerseusDebug} from "@khanacademy/perseus-core";
|
|
6
|
+
|
|
7
|
+
const libName = "@khanacademy/math-input";
|
|
8
|
+
export const libVersion = "__lib_version__";
|
|
9
|
+
|
|
10
|
+
addLibraryVersionToPerseusDebug(libName, libVersion);
|