@khanacademy/math-input 0.7.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/dist/actions/index.d.ts +31 -0
- package/dist/actions/index.js.flow +40 -0
- package/dist/components/compute-layout-parameters.d.ts +38 -0
- package/dist/components/compute-layout-parameters.js.flow +49 -0
- package/dist/components/corner-decal.d.ts +12 -0
- package/dist/components/corner-decal.js.flow +15 -0
- package/dist/components/echo-manager.d.ts +26 -0
- package/dist/components/echo-manager.js.flow +29 -0
- package/dist/components/empty-keypad-button.d.ts +13 -0
- package/dist/components/empty-keypad-button.js.flow +23 -0
- package/dist/components/expression-keypad.d.ts +22 -0
- package/dist/components/expression-keypad.js.flow +32 -0
- package/dist/components/fraction-keypad.d.ts +21 -0
- package/dist/components/fraction-keypad.js.flow +30 -0
- package/dist/components/gesture-manager.d.ts +74 -0
- package/dist/components/gesture-manager.js.flow +82 -0
- package/dist/components/gesture-state-machine.d.ts +105 -0
- package/dist/components/gesture-state-machine.js.flow +118 -0
- package/dist/components/icon.d.ts +15 -0
- package/dist/components/icon.js.flow +18 -0
- package/dist/components/input/__tests__/test-math-wrapper.d.ts +8 -0
- package/dist/components/input/__tests__/test-math-wrapper.js.flow +14 -0
- package/dist/components/input/cursor-handle.d.ts +1 -1
- package/dist/components/input/cursor-handle.js.flow +1 -1
- package/dist/components/input/drag-listener.d.ts +13 -0
- package/dist/components/input/drag-listener.js.flow +19 -0
- package/dist/components/input/math-input.d.ts +5 -4
- package/dist/components/input/math-input.js.flow +5 -4
- package/dist/components/input/math-wrapper.d.ts +110 -0
- package/dist/components/input/math-wrapper.js.flow +125 -0
- package/dist/components/input/scroll-into-view.d.ts +11 -0
- package/dist/components/input/scroll-into-view.js.flow +20 -0
- package/dist/components/keypad/button-assets.d.ts +4 -3
- package/dist/components/keypad/button-assets.js.flow +3 -3
- package/dist/components/keypad/button.d.ts +1 -2
- package/dist/components/keypad/button.js.flow +1 -2
- package/dist/components/keypad/keypad-page-items.d.ts +15 -10
- package/dist/components/keypad/keypad-page-items.js.flow +20 -10
- package/dist/components/keypad-button.d.ts +52 -0
- package/dist/components/keypad-button.js.flow +79 -0
- package/dist/components/keypad-container.d.ts +40 -0
- package/dist/components/keypad-container.js.flow +58 -0
- package/dist/components/keypad.d.ts +31 -0
- package/dist/components/keypad.js.flow +40 -0
- package/dist/components/many-keypad-button.d.ts +15 -0
- package/dist/components/many-keypad-button.js.flow +17 -0
- package/dist/components/math-icon.d.ts +16 -0
- package/dist/components/math-icon.js.flow +19 -0
- package/dist/components/multi-symbol-grid.d.ts +14 -0
- package/dist/components/multi-symbol-grid.js.flow +16 -0
- package/dist/components/multi-symbol-popover.d.ts +12 -0
- package/dist/components/multi-symbol-popover.js.flow +15 -0
- package/dist/components/navigation-pad.d.ts +14 -0
- package/dist/components/navigation-pad.js.flow +16 -0
- package/dist/components/node-manager.d.ts +53 -0
- package/dist/components/node-manager.js.flow +65 -0
- package/dist/components/popover-manager.d.ts +13 -0
- package/dist/components/popover-manager.js.flow +15 -0
- package/dist/components/popover-state-machine.d.ts +75 -0
- package/dist/components/popover-state-machine.js.flow +83 -0
- package/dist/components/provided-keypad.d.ts +8 -7
- package/dist/components/provided-keypad.js.flow +8 -7
- package/dist/components/styles.d.ts +6 -0
- package/dist/components/styles.js.flow +13 -0
- package/dist/components/svg-icon.d.ts +12 -0
- package/dist/components/svg-icon.js.flow +15 -0
- package/dist/components/tabbar/icons.d.ts +3 -2
- package/dist/components/tabbar/icons.js.flow +3 -2
- package/dist/components/tabbar/item.d.ts +1 -2
- package/dist/components/tabbar/item.js.flow +1 -2
- package/dist/components/tabbar/tabbar.d.ts +3 -3
- package/dist/components/tabbar/tabbar.js.flow +3 -3
- package/dist/components/text-icon.d.ts +13 -0
- package/dist/components/text-icon.js.flow +16 -0
- package/dist/components/touchable-keypad-button.d.ts +30 -0
- package/dist/components/touchable-keypad-button.js.flow +35 -0
- package/dist/components/two-page-keypad.d.ts +20 -0
- package/dist/components/two-page-keypad.js.flow +30 -0
- package/dist/components/velocity-tracker.d.ts +48 -0
- package/dist/components/velocity-tracker.js.flow +54 -0
- package/dist/es/index.js +938 -1059
- package/dist/es/index.js.map +1 -1
- package/dist/fake-react-native-web/text.d.ts +2 -1
- package/dist/fake-react-native-web/text.js.flow +2 -1
- package/dist/fake-react-native-web/view.d.ts +3 -2
- package/dist/fake-react-native-web/view.js.flow +3 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +988 -1089
- package/dist/index.js.flow +1 -4
- package/dist/index.js.map +1 -1
- package/dist/store/echo-reducer.d.ts +5 -0
- package/dist/store/echo-reducer.js.flow +14 -0
- package/dist/store/index.d.ts +46 -1
- package/dist/store/index.js.flow +64 -1
- package/dist/store/input-reducer.d.ts +7 -0
- package/dist/store/input-reducer.js.flow +16 -0
- package/dist/store/keypad-reducer.d.ts +9 -0
- package/dist/store/keypad-reducer.js.flow +18 -0
- package/dist/store/layout-reducer.d.ts +21 -0
- package/dist/store/layout-reducer.js.flow +30 -0
- package/dist/store/pager-reducer.d.ts +13 -0
- package/dist/store/pager-reducer.js.flow +22 -0
- package/dist/store/shared.d.ts +6 -0
- package/dist/store/shared.js.flow +13 -0
- package/dist/store/types.d.ts +57 -0
- package/dist/store/types.js.flow +63 -0
- package/dist/types.d.ts +50 -0
- package/dist/types.js.flow +61 -0
- package/package.json +1 -1
- package/src/actions/{index.js → index.ts} +5 -5
- package/src/components/__tests__/{gesture-state-machine_test.js → gesture-state-machine.test.ts} +5 -1
- package/src/components/__tests__/{two-page-keypad_test.js → two-page-keypad.test.tsx} +0 -2
- package/src/components/{corner-decal.js → corner-decal.tsx} +6 -5
- package/src/components/{echo-manager.js → echo-manager.tsx} +29 -24
- package/src/components/{empty-keypad-button.js → empty-keypad-button.tsx} +17 -10
- package/src/components/{expression-keypad.js → expression-keypad.tsx} +27 -25
- package/src/components/{fraction-keypad.js → fraction-keypad.tsx} +21 -16
- package/src/components/{gesture-manager.js → gesture-manager.tsx} +10 -4
- package/src/components/{gesture-state-machine.js → gesture-state-machine.ts} +49 -3
- package/src/components/{icon.js → icon.tsx} +12 -14
- package/src/components/input/cursor-handle.tsx +1 -1
- package/src/components/input/{drag-listener.js → drag-listener.ts} +4 -0
- package/src/components/input/math-input.tsx +10 -9
- package/src/components/input/{math-wrapper.js → math-wrapper.ts} +10 -6
- package/src/components/input/{scroll-into-view.js → scroll-into-view.ts} +5 -15
- package/src/components/keypad/button-assets.tsx +4 -5
- package/src/components/keypad/button.tsx +1 -2
- package/src/components/keypad/index.tsx +1 -1
- package/src/components/keypad/keypad-page-items.tsx +33 -10
- package/src/components/{keypad-button.js → keypad-button.tsx} +42 -37
- package/src/components/{keypad-container.js → keypad-container.tsx} +41 -23
- package/src/components/{keypad.js → keypad.tsx} +31 -23
- package/src/components/{many-keypad-button.js → many-keypad-button.tsx} +8 -6
- package/src/components/{math-icon.js → math-icon.tsx} +7 -6
- package/src/components/{multi-symbol-grid.js → multi-symbol-grid.tsx} +8 -8
- package/src/components/{multi-symbol-popover.js → multi-symbol-popover.tsx} +5 -6
- package/src/components/{navigation-pad.js → navigation-pad.tsx} +7 -6
- package/src/components/{node-manager.js → node-manager.ts} +16 -4
- package/src/components/{popover-manager.js → popover-manager.tsx} +13 -16
- package/src/components/{popover-state-machine.js → popover-state-machine.ts} +21 -2
- package/src/components/prop-types.js +1 -67
- package/src/components/provided-keypad.tsx +14 -12
- package/src/components/{svg-icon.js → svg-icon.tsx} +5 -6
- package/src/components/tabbar/icons.tsx +4 -2
- package/src/components/tabbar/item.tsx +1 -3
- package/src/components/tabbar/{tabbar.stories.js → tabbar.stories.tsx} +10 -1
- package/src/components/tabbar/tabbar.tsx +3 -3
- package/src/components/{text-icon.js → text-icon.tsx} +7 -6
- package/src/components/{touchable-keypad-button.js → touchable-keypad-button.tsx} +19 -16
- package/src/components/{two-page-keypad.js → two-page-keypad.tsx} +13 -9
- package/src/components/{velocity-tracker.js → velocity-tracker.ts} +14 -4
- package/src/fake-react-native-web/text.tsx +2 -1
- package/src/fake-react-native-web/view.tsx +3 -2
- package/src/index.ts +1 -4
- package/src/store/echo-reducer.ts +58 -0
- package/src/store/index.ts +14 -425
- package/src/store/input-reducer.ts +55 -0
- package/src/store/keypad-reducer.ts +62 -0
- package/src/store/layout-reducer.ts +133 -0
- package/src/store/pager-reducer.ts +141 -0
- package/src/store/shared.ts +12 -0
- package/src/store/types.ts +65 -0
- package/src/types.ts +69 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/src/components/app.js +0 -73
- package/src/demo.js +0 -9
- package/src/native-app.js +0 -85
- /package/src/components/__tests__/{node-manager_test.js → node-manager.test.ts} +0 -0
- /package/src/components/{compute-layout-parameters.js → compute-layout-parameters.ts} +0 -0
- /package/src/components/input/__tests__/{context-tracking_test.js → context-tracking.test.ts} +0 -0
- /package/src/components/input/__tests__/{mathquill_test.js → mathquill.test.ts} +0 -0
- /package/src/components/input/__tests__/{test-math-wrapper.jsx → test-math-wrapper.ts} +0 -0
- /package/src/components/keypad/{button.stories.js → button.stories.tsx} +0 -0
- /package/src/components/{styles.js → styles.ts} +0 -0
- /package/src/components/tabbar/__tests__/{tabbar_test.js → tabbar.test.tsx} +0 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import {EchoAnimationTypes, KeyTypes} from "../consts";
|
|
2
|
+
import KeyConfigs from "../data/key-configs";
|
|
3
|
+
|
|
4
|
+
import type {EchoState} from "./types";
|
|
5
|
+
|
|
6
|
+
// Used to generate unique animation IDs for the echo animations. The actual
|
|
7
|
+
// values are irrelevant as long as they are unique.
|
|
8
|
+
let _lastAnimationId = 0;
|
|
9
|
+
|
|
10
|
+
const initialEchoState = {
|
|
11
|
+
echoes: [],
|
|
12
|
+
} as const;
|
|
13
|
+
|
|
14
|
+
const echoReducer = function (state = initialEchoState, action): EchoState {
|
|
15
|
+
switch (action.type) {
|
|
16
|
+
case "PressKey":
|
|
17
|
+
const keyConfig = KeyConfigs[action.key];
|
|
18
|
+
|
|
19
|
+
// Add in the echo animation if the user performs a math
|
|
20
|
+
// operation.
|
|
21
|
+
if (
|
|
22
|
+
keyConfig.type === KeyTypes.VALUE ||
|
|
23
|
+
keyConfig.type === KeyTypes.OPERATOR
|
|
24
|
+
) {
|
|
25
|
+
return {
|
|
26
|
+
...state,
|
|
27
|
+
echoes: [
|
|
28
|
+
...state.echoes,
|
|
29
|
+
{
|
|
30
|
+
animationId: "" + _lastAnimationId++,
|
|
31
|
+
animationType: action.inPopover
|
|
32
|
+
? EchoAnimationTypes.LONG_FADE_ONLY
|
|
33
|
+
: EchoAnimationTypes.FADE_ONLY,
|
|
34
|
+
borders: action.borders,
|
|
35
|
+
id: keyConfig.id,
|
|
36
|
+
initialBounds: action.initialBounds,
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return state;
|
|
42
|
+
|
|
43
|
+
case "RemoveEcho":
|
|
44
|
+
const remainingEchoes = state.echoes.filter((echo) => {
|
|
45
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'animationId' does not exist on type 'never'.
|
|
46
|
+
return echo.animationId !== action.animationId;
|
|
47
|
+
});
|
|
48
|
+
return {
|
|
49
|
+
...state,
|
|
50
|
+
echoes: remainingEchoes,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
default:
|
|
54
|
+
return state;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export default echoReducer;
|
package/src/store/index.ts
CHANGED
|
@@ -1,261 +1,20 @@
|
|
|
1
1
|
import * as Redux from "redux";
|
|
2
2
|
|
|
3
|
-
import {tabletCutoffPx} from "../components/common-style";
|
|
4
|
-
import {computeLayoutParameters} from "../components/compute-layout-parameters";
|
|
5
|
-
import ExpressionKeypad from "../components/expression-keypad";
|
|
6
|
-
import FractionKeypad from "../components/fraction-keypad";
|
|
7
3
|
import GestureManager from "../components/gesture-manager";
|
|
8
|
-
import * as CursorContexts from "../components/input/cursor-contexts";
|
|
9
|
-
import VelocityTracker from "../components/velocity-tracker";
|
|
10
|
-
import {
|
|
11
|
-
DeviceOrientations,
|
|
12
|
-
DeviceTypes,
|
|
13
|
-
EchoAnimationTypes,
|
|
14
|
-
KeyTypes,
|
|
15
|
-
KeypadTypes,
|
|
16
|
-
LayoutModes,
|
|
17
|
-
} from "../consts";
|
|
18
|
-
import KeyConfigs from "../data/key-configs";
|
|
19
4
|
import Keys from "../data/keys";
|
|
20
5
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
6
|
+
import echoReducer from "./echo-reducer";
|
|
7
|
+
import inputReducer from "./input-reducer";
|
|
8
|
+
import keypadReducer from "./keypad-reducer";
|
|
9
|
+
import layoutReducer from "./layout-reducer";
|
|
10
|
+
import pagerReducer from "./pager-reducer";
|
|
11
|
+
import {defaultKeypadType, keypadForType} from "./shared";
|
|
25
12
|
|
|
26
|
-
|
|
27
|
-
const initialInputState: {
|
|
28
|
-
keyHandler: any;
|
|
29
|
-
cursor: any;
|
|
30
|
-
} = {
|
|
31
|
-
keyHandler: null,
|
|
32
|
-
cursor: {
|
|
33
|
-
context: CursorContexts.NONE,
|
|
34
|
-
},
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
const inputReducer = function (state = initialInputState, action: any) {
|
|
38
|
-
switch (action.type) {
|
|
39
|
-
case "SetKeyHandler":
|
|
40
|
-
return {
|
|
41
|
-
...state,
|
|
42
|
-
keyHandler: action.keyHandler,
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
case "PressKey":
|
|
46
|
-
const keyConfig = KeyConfigs[action.key];
|
|
47
|
-
if (keyConfig.type !== KeyTypes.KEYPAD_NAVIGATION) {
|
|
48
|
-
// This is probably an anti-pattern but it works for the
|
|
49
|
-
// case where we don't actually control the state but we
|
|
50
|
-
// still want to communicate with the other object
|
|
51
|
-
return {
|
|
52
|
-
...state,
|
|
53
|
-
cursor: state.keyHandler(keyConfig.id),
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// TODO(kevinb) get state from MathQuill and store it?
|
|
58
|
-
return state;
|
|
59
|
-
|
|
60
|
-
case "SetCursor":
|
|
61
|
-
return {
|
|
62
|
-
...state,
|
|
63
|
-
cursor: action.cursor,
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
default:
|
|
67
|
-
return state;
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
const defaultKeypadType = KeypadTypes.EXPRESSION;
|
|
72
|
-
|
|
73
|
-
const initialKeypadState = {
|
|
74
|
-
extraKeys: ["x", "y", Keys.THETA, Keys.PI],
|
|
75
|
-
keypadType: defaultKeypadType,
|
|
76
|
-
active: false,
|
|
77
|
-
} as const;
|
|
78
|
-
|
|
79
|
-
const keypadReducer = function (
|
|
80
|
-
state = initialKeypadState,
|
|
81
|
-
action: {
|
|
82
|
-
type: string;
|
|
83
|
-
},
|
|
84
|
-
) {
|
|
85
|
-
switch (action.type) {
|
|
86
|
-
case "DismissKeypad":
|
|
87
|
-
return {
|
|
88
|
-
...state,
|
|
89
|
-
active: false,
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
case "ActivateKeypad":
|
|
93
|
-
return {
|
|
94
|
-
...state,
|
|
95
|
-
active: true,
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
case "ConfigureKeypad":
|
|
99
|
-
return {
|
|
100
|
-
...state,
|
|
101
|
-
// Default `extraKeys` to the empty array.
|
|
102
|
-
extraKeys: [],
|
|
103
|
-
// @ts-expect-error [FEI-5003] - TS2339 - Property 'configuration' does not exist on type '{ type: string; }'.
|
|
104
|
-
...action.configuration,
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
case "PressKey":
|
|
108
|
-
// @ts-expect-error [FEI-5003] - TS2339 - Property 'key' does not exist on type '{ type: string; }'.
|
|
109
|
-
const keyConfig = KeyConfigs[action.key];
|
|
110
|
-
// NOTE(charlie): Our keypad system operates by triggering key
|
|
111
|
-
// presses with key IDs in a dumb manner, such that the keys
|
|
112
|
-
// don't know what they can do--instead, the store is
|
|
113
|
-
// responsible for interpreting key presses and triggering the
|
|
114
|
-
// right actions when they occur. Hence, we figure off a
|
|
115
|
-
// dismissal here rather than dispatching a dismiss action in
|
|
116
|
-
// the first place.
|
|
117
|
-
if (keyConfig.id === Keys.DISMISS) {
|
|
118
|
-
return keypadReducer(state, {type: "DismissKeypad"});
|
|
119
|
-
}
|
|
120
|
-
return state;
|
|
121
|
-
|
|
122
|
-
default:
|
|
123
|
-
return state;
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
// We default to the right-most page. This is done so-as to enforce a
|
|
128
|
-
// consistent orientation between the view pager layout and the flattened
|
|
129
|
-
// layout, where our default page appears on the far right.
|
|
130
|
-
const getDefaultPage = (numPages) => numPages - 1;
|
|
131
|
-
|
|
132
|
-
const initialPagerState = {
|
|
133
|
-
animateToPosition: false,
|
|
134
|
-
currentPage: getDefaultPage(keypadForType[defaultKeypadType].numPages),
|
|
135
|
-
// The cumulative differential in the horizontal direction for the
|
|
136
|
-
// current swipe.
|
|
137
|
-
dx: 0,
|
|
138
|
-
numPages: keypadForType[defaultKeypadType].numPages,
|
|
139
|
-
pageWidthPx: 0,
|
|
140
|
-
velocityTracker: new VelocityTracker(),
|
|
141
|
-
} as const;
|
|
142
|
-
|
|
143
|
-
const pagerReducer = function (
|
|
144
|
-
state = initialPagerState,
|
|
145
|
-
action: {
|
|
146
|
-
type: string;
|
|
147
|
-
},
|
|
148
|
-
) {
|
|
149
|
-
switch (action.type) {
|
|
150
|
-
case "ConfigureKeypad":
|
|
151
|
-
// @ts-expect-error [FEI-5003] - TS2339 - Property 'configuration' does not exist on type '{ type: string; }'.
|
|
152
|
-
const {keypadType} = action.configuration;
|
|
153
|
-
const {numPages} = keypadForType[keypadType];
|
|
154
|
-
return {
|
|
155
|
-
...state,
|
|
156
|
-
numPages,
|
|
157
|
-
animateToPosition: false,
|
|
158
|
-
currentPage: getDefaultPage(numPages),
|
|
159
|
-
dx: 0,
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
case "SetPageSize":
|
|
163
|
-
return {
|
|
164
|
-
...state,
|
|
165
|
-
// @ts-expect-error [FEI-5003] - TS2339 - Property 'pageWidthPx' does not exist on type '{ type: string; }'.
|
|
166
|
-
pageWidthPx: action.pageWidthPx,
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
case "PressKey":
|
|
170
|
-
// @ts-expect-error [FEI-5003] - TS2339 - Property 'key' does not exist on type '{ type: string; }'.
|
|
171
|
-
const keyConfig = KeyConfigs[action.key];
|
|
172
|
-
|
|
173
|
-
// Reset the keypad page if the user performs a math operation.
|
|
174
|
-
if (
|
|
175
|
-
keyConfig.type === KeyTypes.VALUE ||
|
|
176
|
-
keyConfig.type === KeyTypes.OPERATOR
|
|
177
|
-
) {
|
|
178
|
-
return pagerReducer(state, {type: "ResetKeypadPage"});
|
|
179
|
-
}
|
|
180
|
-
return state;
|
|
181
|
-
|
|
182
|
-
case "ResetKeypadPage":
|
|
183
|
-
return {
|
|
184
|
-
...state,
|
|
185
|
-
animateToPosition: true,
|
|
186
|
-
// We start at the right-most page.
|
|
187
|
-
currentPage: getDefaultPage(state.numPages),
|
|
188
|
-
dx: 0,
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
case "PageKeypadRight":
|
|
192
|
-
const nextPage = Math.min(
|
|
193
|
-
state.currentPage + 1,
|
|
194
|
-
state.numPages - 1,
|
|
195
|
-
);
|
|
196
|
-
return {
|
|
197
|
-
...state,
|
|
198
|
-
animateToPosition: true,
|
|
199
|
-
currentPage: nextPage,
|
|
200
|
-
dx: 0,
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
case "PageKeypadLeft":
|
|
204
|
-
const prevPage = Math.max(state.currentPage - 1, 0);
|
|
205
|
-
return {
|
|
206
|
-
...state,
|
|
207
|
-
animateToPosition: true,
|
|
208
|
-
currentPage: prevPage,
|
|
209
|
-
dx: 0,
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
case "OnSwipeChange":
|
|
213
|
-
// @ts-expect-error [FEI-5003] - TS2339 - Property 'dx' does not exist on type '{ type: string; }'.
|
|
214
|
-
state.velocityTracker.push(action.dx);
|
|
215
|
-
|
|
216
|
-
return {
|
|
217
|
-
...state,
|
|
218
|
-
animateToPosition: false,
|
|
219
|
-
// @ts-expect-error [FEI-5003] - TS2339 - Property 'dx' does not exist on type '{ type: string; }'.
|
|
220
|
-
dx: action.dx,
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
case "OnSwipeEnd":
|
|
224
|
-
const {pageWidthPx, velocityTracker} = state;
|
|
225
|
-
// @ts-expect-error [FEI-5003] - TS2339 - Property 'dx' does not exist on type '{ type: string; }'.
|
|
226
|
-
const {dx} = action;
|
|
227
|
-
const velocity = velocityTracker.getVelocity();
|
|
228
|
-
|
|
229
|
-
// NOTE(charlie): These will need refinement. The velocity comes
|
|
230
|
-
// from Framer.
|
|
231
|
-
const minFlingVelocity = 0.1;
|
|
232
|
-
const minFlingDistance = 10;
|
|
233
|
-
|
|
234
|
-
const shouldPageRight =
|
|
235
|
-
dx < -pageWidthPx / 2 ||
|
|
236
|
-
(velocity < -minFlingVelocity && dx < -minFlingDistance);
|
|
237
|
-
|
|
238
|
-
const shouldPageLeft =
|
|
239
|
-
dx > pageWidthPx / 2 ||
|
|
240
|
-
(velocity > minFlingVelocity && dx > minFlingDistance);
|
|
241
|
-
|
|
242
|
-
if (shouldPageRight) {
|
|
243
|
-
return pagerReducer(state, {type: "PageKeypadRight"});
|
|
244
|
-
} else if (shouldPageLeft) {
|
|
245
|
-
return pagerReducer(state, {type: "PageKeypadLeft"});
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
return {
|
|
249
|
-
...state,
|
|
250
|
-
animateToPosition: true,
|
|
251
|
-
dx: 0,
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
default:
|
|
255
|
-
return state;
|
|
256
|
-
}
|
|
257
|
-
};
|
|
13
|
+
import type {GestureState} from "./types";
|
|
258
14
|
|
|
15
|
+
export const createStore = () => {
|
|
16
|
+
// TODO(matthewc)[LC-752]: gestureReducer can't be moved from this file
|
|
17
|
+
// because it depends on `store` being in scope (see note below)
|
|
259
18
|
const createGestureManager = (swipeEnabled: boolean) => {
|
|
260
19
|
return new GestureManager(
|
|
261
20
|
{
|
|
@@ -302,7 +61,10 @@ export const createStore = (): any => {
|
|
|
302
61
|
),
|
|
303
62
|
} as const;
|
|
304
63
|
|
|
305
|
-
const gestureReducer = function (
|
|
64
|
+
const gestureReducer = function (
|
|
65
|
+
state = initialGestureState,
|
|
66
|
+
action: any,
|
|
67
|
+
): GestureState {
|
|
306
68
|
switch (action.type) {
|
|
307
69
|
case "DismissKeypad":
|
|
308
70
|
// NOTE(charlie): In the past, we enforced the "gesture manager
|
|
@@ -342,179 +104,6 @@ export const createStore = (): any => {
|
|
|
342
104
|
}
|
|
343
105
|
};
|
|
344
106
|
|
|
345
|
-
// Used to generate unique animation IDs for the echo animations. The actual
|
|
346
|
-
// values are irrelevant as long as they are unique.
|
|
347
|
-
let _lastAnimationId = 0;
|
|
348
|
-
|
|
349
|
-
const initialEchoState = {
|
|
350
|
-
echoes: [],
|
|
351
|
-
} as const;
|
|
352
|
-
|
|
353
|
-
const echoReducer = function (state = initialEchoState, action) {
|
|
354
|
-
switch (action.type) {
|
|
355
|
-
case "PressKey":
|
|
356
|
-
const keyConfig = KeyConfigs[action.key];
|
|
357
|
-
|
|
358
|
-
// Add in the echo animation if the user performs a math
|
|
359
|
-
// operation.
|
|
360
|
-
if (
|
|
361
|
-
keyConfig.type === KeyTypes.VALUE ||
|
|
362
|
-
keyConfig.type === KeyTypes.OPERATOR
|
|
363
|
-
) {
|
|
364
|
-
return {
|
|
365
|
-
...state,
|
|
366
|
-
echoes: [
|
|
367
|
-
...state.echoes,
|
|
368
|
-
{
|
|
369
|
-
animationId: "" + _lastAnimationId++,
|
|
370
|
-
animationType: action.inPopover
|
|
371
|
-
? EchoAnimationTypes.LONG_FADE_ONLY
|
|
372
|
-
: EchoAnimationTypes.FADE_ONLY,
|
|
373
|
-
borders: action.borders,
|
|
374
|
-
id: keyConfig.id,
|
|
375
|
-
initialBounds: action.initialBounds,
|
|
376
|
-
},
|
|
377
|
-
],
|
|
378
|
-
};
|
|
379
|
-
}
|
|
380
|
-
return state;
|
|
381
|
-
|
|
382
|
-
case "RemoveEcho":
|
|
383
|
-
const remainingEchoes = state.echoes.filter((echo) => {
|
|
384
|
-
// @ts-expect-error [FEI-5003] - TS2339 - Property 'animationId' does not exist on type 'never'.
|
|
385
|
-
return echo.animationId !== action.animationId;
|
|
386
|
-
});
|
|
387
|
-
return {
|
|
388
|
-
...state,
|
|
389
|
-
echoes: remainingEchoes,
|
|
390
|
-
};
|
|
391
|
-
|
|
392
|
-
default:
|
|
393
|
-
return state;
|
|
394
|
-
}
|
|
395
|
-
};
|
|
396
|
-
|
|
397
|
-
const initialLayoutState = {
|
|
398
|
-
gridDimensions: {
|
|
399
|
-
numRows: keypadForType[defaultKeypadType].rows,
|
|
400
|
-
numColumns: keypadForType[defaultKeypadType].columns,
|
|
401
|
-
numMaxVisibleRows: keypadForType[defaultKeypadType].maxVisibleRows,
|
|
402
|
-
numPages: keypadForType[defaultKeypadType].numPages,
|
|
403
|
-
},
|
|
404
|
-
buttonDimensions: {
|
|
405
|
-
widthPx: 48,
|
|
406
|
-
heightPx: 48,
|
|
407
|
-
},
|
|
408
|
-
pageDimensions: {
|
|
409
|
-
pageWidthPx: 0,
|
|
410
|
-
pageHeightPx: 0,
|
|
411
|
-
},
|
|
412
|
-
layoutMode: LayoutModes.FULLSCREEN,
|
|
413
|
-
paginationEnabled: false,
|
|
414
|
-
navigationPadEnabled: false,
|
|
415
|
-
} as const;
|
|
416
|
-
|
|
417
|
-
/**
|
|
418
|
-
* Compute the additional layout state based on the provided page and grid
|
|
419
|
-
* dimensions.
|
|
420
|
-
*/
|
|
421
|
-
const layoutParametersForDimensions = (
|
|
422
|
-
pageDimensions:
|
|
423
|
-
| {
|
|
424
|
-
pageHeightPx: never;
|
|
425
|
-
pageWidthPx: never;
|
|
426
|
-
}
|
|
427
|
-
| {
|
|
428
|
-
pageHeightPx: number;
|
|
429
|
-
pageWidthPx: number;
|
|
430
|
-
},
|
|
431
|
-
gridDimensions,
|
|
432
|
-
) => {
|
|
433
|
-
const {pageWidthPx, pageHeightPx} = pageDimensions;
|
|
434
|
-
|
|
435
|
-
// Determine the device type and orientation.
|
|
436
|
-
const deviceOrientation =
|
|
437
|
-
pageWidthPx > pageHeightPx
|
|
438
|
-
? DeviceOrientations.LANDSCAPE
|
|
439
|
-
: DeviceOrientations.PORTRAIT;
|
|
440
|
-
const deviceType =
|
|
441
|
-
Math.min(pageWidthPx, pageHeightPx) > tabletCutoffPx
|
|
442
|
-
? DeviceTypes.TABLET
|
|
443
|
-
: DeviceTypes.PHONE;
|
|
444
|
-
|
|
445
|
-
// Using that information, make some decisions (or assumptions)
|
|
446
|
-
// about the resulting layout.
|
|
447
|
-
const navigationPadEnabled = deviceType === DeviceTypes.TABLET;
|
|
448
|
-
const paginationEnabled =
|
|
449
|
-
deviceType === DeviceTypes.PHONE &&
|
|
450
|
-
deviceOrientation === DeviceOrientations.PORTRAIT;
|
|
451
|
-
|
|
452
|
-
const deviceInfo = {deviceOrientation, deviceType} as const;
|
|
453
|
-
const layoutOptions = {
|
|
454
|
-
navigationPadEnabled,
|
|
455
|
-
paginationEnabled,
|
|
456
|
-
// HACK(charlie): It's not great that we're making assumptions about
|
|
457
|
-
// the toolbar (which is rendered by webapp, and should always be
|
|
458
|
-
// visible and anchored to the bottom of the page for phone and
|
|
459
|
-
// tablet exercises). But this is primarily a heuristic (the goal is
|
|
460
|
-
// to preserve a 'good' amount of space between the top of the
|
|
461
|
-
// keypad and the top of the page) so we afford to have some margin
|
|
462
|
-
// of error.
|
|
463
|
-
toolbarEnabled: true,
|
|
464
|
-
} as const;
|
|
465
|
-
|
|
466
|
-
return {
|
|
467
|
-
...computeLayoutParameters(
|
|
468
|
-
gridDimensions,
|
|
469
|
-
pageDimensions,
|
|
470
|
-
deviceInfo,
|
|
471
|
-
layoutOptions,
|
|
472
|
-
),
|
|
473
|
-
// Pass along some of the layout information, so that other
|
|
474
|
-
// components in the heirarchy can adapt appropriately.
|
|
475
|
-
navigationPadEnabled,
|
|
476
|
-
paginationEnabled,
|
|
477
|
-
};
|
|
478
|
-
};
|
|
479
|
-
|
|
480
|
-
const layoutReducer = function (state = initialLayoutState, action: any) {
|
|
481
|
-
switch (action.type) {
|
|
482
|
-
case "ConfigureKeypad":
|
|
483
|
-
const {keypadType} = action.configuration;
|
|
484
|
-
const gridDimensions = {
|
|
485
|
-
numRows: keypadForType[keypadType].rows,
|
|
486
|
-
numColumns: keypadForType[keypadType].columns,
|
|
487
|
-
numMaxVisibleRows: keypadForType[keypadType].maxVisibleRows,
|
|
488
|
-
numPages: keypadForType[keypadType].numPages,
|
|
489
|
-
} as const;
|
|
490
|
-
|
|
491
|
-
return {
|
|
492
|
-
...state,
|
|
493
|
-
...layoutParametersForDimensions(
|
|
494
|
-
state.pageDimensions,
|
|
495
|
-
gridDimensions,
|
|
496
|
-
),
|
|
497
|
-
gridDimensions,
|
|
498
|
-
};
|
|
499
|
-
|
|
500
|
-
case "SetPageSize":
|
|
501
|
-
const {pageWidthPx, pageHeightPx} = action;
|
|
502
|
-
const pageDimensions = {pageWidthPx, pageHeightPx} as const;
|
|
503
|
-
|
|
504
|
-
return {
|
|
505
|
-
...state,
|
|
506
|
-
...layoutParametersForDimensions(
|
|
507
|
-
pageDimensions,
|
|
508
|
-
state.gridDimensions,
|
|
509
|
-
),
|
|
510
|
-
pageDimensions,
|
|
511
|
-
};
|
|
512
|
-
|
|
513
|
-
default:
|
|
514
|
-
return state;
|
|
515
|
-
}
|
|
516
|
-
};
|
|
517
|
-
|
|
518
107
|
const reducer = Redux.combineReducers({
|
|
519
108
|
input: inputReducer,
|
|
520
109
|
keypad: keypadReducer,
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import * as CursorContexts from "../components/input/cursor-contexts";
|
|
2
|
+
import {KeyTypes} from "../consts";
|
|
3
|
+
import KeyConfigs from "../data/key-configs";
|
|
4
|
+
|
|
5
|
+
import type {Cursor, KeyHandler} from "../types";
|
|
6
|
+
import type {InputState} from "./types";
|
|
7
|
+
|
|
8
|
+
const initialInputState: {
|
|
9
|
+
keyHandler: KeyHandler | null;
|
|
10
|
+
cursor: Cursor;
|
|
11
|
+
} = {
|
|
12
|
+
keyHandler: null,
|
|
13
|
+
cursor: {
|
|
14
|
+
context: CursorContexts.NONE,
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const inputReducer = function (
|
|
19
|
+
state = initialInputState,
|
|
20
|
+
action: any,
|
|
21
|
+
): InputState {
|
|
22
|
+
switch (action.type) {
|
|
23
|
+
case "SetKeyHandler":
|
|
24
|
+
return {
|
|
25
|
+
...state,
|
|
26
|
+
keyHandler: action.keyHandler,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
case "PressKey":
|
|
30
|
+
const keyConfig = KeyConfigs[action.key];
|
|
31
|
+
if (keyConfig.type !== KeyTypes.KEYPAD_NAVIGATION) {
|
|
32
|
+
// This is probably an anti-pattern but it works for the
|
|
33
|
+
// case where we don't actually control the state but we
|
|
34
|
+
// still want to communicate with the other object
|
|
35
|
+
return {
|
|
36
|
+
...state,
|
|
37
|
+
cursor: state.keyHandler?.(keyConfig.id),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// TODO(kevinb) get state from MathQuill and store it?
|
|
42
|
+
return state;
|
|
43
|
+
|
|
44
|
+
case "SetCursor":
|
|
45
|
+
return {
|
|
46
|
+
...state,
|
|
47
|
+
cursor: action.cursor,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
default:
|
|
51
|
+
return state;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export default inputReducer;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import KeyConfigs from "../data/key-configs";
|
|
2
|
+
import Keys from "../data/keys";
|
|
3
|
+
|
|
4
|
+
import {defaultKeypadType} from "./shared";
|
|
5
|
+
|
|
6
|
+
import type {KeypadState} from "./types";
|
|
7
|
+
|
|
8
|
+
const initialKeypadState = {
|
|
9
|
+
extraKeys: ["x", "y", Keys.THETA, Keys.PI],
|
|
10
|
+
keypadType: defaultKeypadType,
|
|
11
|
+
active: false,
|
|
12
|
+
} as const;
|
|
13
|
+
|
|
14
|
+
const keypadReducer = function (
|
|
15
|
+
state = initialKeypadState,
|
|
16
|
+
action: {
|
|
17
|
+
type: string;
|
|
18
|
+
},
|
|
19
|
+
): KeypadState {
|
|
20
|
+
switch (action.type) {
|
|
21
|
+
case "DismissKeypad":
|
|
22
|
+
return {
|
|
23
|
+
...state,
|
|
24
|
+
active: false,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
case "ActivateKeypad":
|
|
28
|
+
return {
|
|
29
|
+
...state,
|
|
30
|
+
active: true,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
case "ConfigureKeypad":
|
|
34
|
+
return {
|
|
35
|
+
...state,
|
|
36
|
+
// Default `extraKeys` to the empty array.
|
|
37
|
+
extraKeys: [],
|
|
38
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'configuration' does not exist on type '{ type: string; }'.
|
|
39
|
+
...action.configuration,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
case "PressKey":
|
|
43
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'key' does not exist on type '{ type: string; }'.
|
|
44
|
+
const keyConfig = KeyConfigs[action.key];
|
|
45
|
+
// NOTE(charlie): Our keypad system operates by triggering key
|
|
46
|
+
// presses with key IDs in a dumb manner, such that the keys
|
|
47
|
+
// don't know what they can do--instead, the store is
|
|
48
|
+
// responsible for interpreting key presses and triggering the
|
|
49
|
+
// right actions when they occur. Hence, we figure off a
|
|
50
|
+
// dismissal here rather than dispatching a dismiss action in
|
|
51
|
+
// the first place.
|
|
52
|
+
if (keyConfig.id === Keys.DISMISS) {
|
|
53
|
+
return keypadReducer(state, {type: "DismissKeypad"});
|
|
54
|
+
}
|
|
55
|
+
return state;
|
|
56
|
+
|
|
57
|
+
default:
|
|
58
|
+
return state;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export default keypadReducer;
|