@khanacademy/math-input 15.1.0 → 16.1.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 +24 -0
- package/dist/components/aphrodite-css-transition-group/util.d.ts +2 -1
- package/dist/components/input/math-wrapper.d.ts +1 -1
- 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/data/key-configs.d.ts +1 -1
- package/dist/es/index.js +171 -4744
- package/dist/es/index.js.map +1 -1
- package/dist/fake-react-native-web/view.d.ts +2 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +168 -4722
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/__tests__/integration.test.tsx +2 -3
- package/src/components/input/math-input.tsx +1 -0
- package/src/components/input/math-wrapper.ts +2 -2
- 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/data/key-configs.ts +1 -1
- 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,7 +0,0 @@
|
|
|
1
|
-
import { KeypadType } from "../../../enums";
|
|
2
|
-
declare const defaultKeypadType = KeypadType.EXPRESSION;
|
|
3
|
-
declare const keypadForType: {
|
|
4
|
-
readonly FRACTION: import("../../../types").KeypadLayout;
|
|
5
|
-
readonly EXPRESSION: import("../../../types").KeypadLayout;
|
|
6
|
-
};
|
|
7
|
-
export { keypadForType, defaultKeypadType };
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import type Key from "../../../data/keys";
|
|
2
|
-
import type { LayoutMode, KeypadType } from "../../../enums";
|
|
3
|
-
import type { Cursor, KeyHandler, Popover, Echo } from "../../../types";
|
|
4
|
-
import type GestureManager from "../gesture-manager";
|
|
5
|
-
export interface InputState {
|
|
6
|
-
keyHandler: KeyHandler | null;
|
|
7
|
-
cursor: Cursor | undefined;
|
|
8
|
-
}
|
|
9
|
-
export interface KeypadState {
|
|
10
|
-
extraKeys: ReadonlyArray<string>;
|
|
11
|
-
keypadType: KeypadType;
|
|
12
|
-
active: boolean;
|
|
13
|
-
}
|
|
14
|
-
export interface GestureState {
|
|
15
|
-
popover: Popover | null;
|
|
16
|
-
focus: Key | null;
|
|
17
|
-
gestureManager: GestureManager;
|
|
18
|
-
}
|
|
19
|
-
export interface EchoState {
|
|
20
|
-
echoes: ReadonlyArray<Echo>;
|
|
21
|
-
}
|
|
22
|
-
export type GridDimensions = {
|
|
23
|
-
numRows: number;
|
|
24
|
-
numColumns: number;
|
|
25
|
-
numMaxVisibleRows: number;
|
|
26
|
-
numPages: number;
|
|
27
|
-
};
|
|
28
|
-
export type WidthHeight = {
|
|
29
|
-
width: number;
|
|
30
|
-
height: number;
|
|
31
|
-
};
|
|
32
|
-
export interface LayoutState {
|
|
33
|
-
gridDimensions: GridDimensions;
|
|
34
|
-
buttonDimensions: WidthHeight;
|
|
35
|
-
containerDimensions: WidthHeight;
|
|
36
|
-
pageDimensions: WidthHeight;
|
|
37
|
-
layoutMode: LayoutMode;
|
|
38
|
-
paginationEnabled: boolean;
|
|
39
|
-
navigationPadEnabled: boolean;
|
|
40
|
-
}
|
|
41
|
-
export interface State {
|
|
42
|
-
input: InputState;
|
|
43
|
-
keypad: KeypadState;
|
|
44
|
-
gestures: GestureState;
|
|
45
|
-
echoes: EchoState;
|
|
46
|
-
layout: LayoutState;
|
|
47
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A component that renders a single SVG icon.
|
|
3
|
-
*/
|
|
4
|
-
import * as React from "react";
|
|
5
|
-
type Props = {
|
|
6
|
-
color: string;
|
|
7
|
-
name: string;
|
|
8
|
-
};
|
|
9
|
-
declare class SvgIcon extends React.Component<Props> {
|
|
10
|
-
render(): JSX.Element;
|
|
11
|
-
}
|
|
12
|
-
export default SvgIcon;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A component that renders a text-based icon.
|
|
3
|
-
*/
|
|
4
|
-
import * as React from "react";
|
|
5
|
-
import type { StyleType } from "@khanacademy/wonder-blocks-core";
|
|
6
|
-
type Props = {
|
|
7
|
-
character: string;
|
|
8
|
-
style?: StyleType;
|
|
9
|
-
};
|
|
10
|
-
declare class TextIcon extends React.Component<Props> {
|
|
11
|
-
render(): JSX.Element;
|
|
12
|
-
}
|
|
13
|
-
export default TextIcon;
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A touchable wrapper around the base KeypadButton component. This button is
|
|
3
|
-
* responsible for keeping our button ID system (which will be used to handle
|
|
4
|
-
* touch events globally) opaque to the KeypadButton.
|
|
5
|
-
*/
|
|
6
|
-
import * as React from "react";
|
|
7
|
-
import type Key from "../../data/keys";
|
|
8
|
-
import type { KeyType } from "../../enums";
|
|
9
|
-
import type { Border, IconConfig, KeyConfig } from "../../types";
|
|
10
|
-
import type GestureManager from "./gesture-manager";
|
|
11
|
-
import type { StyleType } from "@khanacademy/wonder-blocks-core";
|
|
12
|
-
interface SharedProps {
|
|
13
|
-
borders?: Border;
|
|
14
|
-
disabled?: boolean;
|
|
15
|
-
style?: StyleType;
|
|
16
|
-
}
|
|
17
|
-
interface OwnProps extends SharedProps {
|
|
18
|
-
keyConfig: KeyConfig;
|
|
19
|
-
}
|
|
20
|
-
interface Props extends SharedProps {
|
|
21
|
-
childKeyIds?: ReadonlyArray<string>;
|
|
22
|
-
gestureManager: GestureManager;
|
|
23
|
-
id: Key;
|
|
24
|
-
focused: boolean;
|
|
25
|
-
popoverEnabled: boolean;
|
|
26
|
-
childKeys?: ReadonlyArray<KeyConfig>;
|
|
27
|
-
ariaLabel?: string;
|
|
28
|
-
icon?: IconConfig;
|
|
29
|
-
type: KeyType;
|
|
30
|
-
}
|
|
31
|
-
declare class TouchableKeypadButton extends React.Component<Props> {
|
|
32
|
-
shouldComponentUpdate(newProps: Props): boolean;
|
|
33
|
-
componentWillUnmount(): void;
|
|
34
|
-
render(): JSX.Element;
|
|
35
|
-
}
|
|
36
|
-
declare const _default: import("react-redux").ConnectedComponent<typeof TouchableKeypadButton, import("react-redux").Omit<React.ClassAttributes<TouchableKeypadButton> & Props, "style" | "ariaLabel" | "type" | "id" | "icon" | "focused" | "disabled" | "childKeyIds" | "borders" | "childKeys" | "popoverEnabled" | "gestureManager"> & OwnProps>;
|
|
37
|
-
export default _default;
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A keypad with two pages of keys.
|
|
3
|
-
*/
|
|
4
|
-
import * as React from "react";
|
|
5
|
-
import type { KeypadPageType } from "../../types";
|
|
6
|
-
interface ReduxProps {
|
|
7
|
-
paginationEnabled: boolean;
|
|
8
|
-
}
|
|
9
|
-
interface Props extends ReduxProps {
|
|
10
|
-
leftPage: React.ReactNode;
|
|
11
|
-
rightPage: React.ReactNode;
|
|
12
|
-
}
|
|
13
|
-
type State = {
|
|
14
|
-
selectedPage: KeypadPageType;
|
|
15
|
-
};
|
|
16
|
-
declare class TwoPageKeypad extends React.Component<Props, State> {
|
|
17
|
-
state: State;
|
|
18
|
-
render(): JSX.Element;
|
|
19
|
-
}
|
|
20
|
-
declare const _default: import("react-redux").ConnectedComponent<typeof TwoPageKeypad, import("react-redux").Omit<React.ClassAttributes<TwoPageKeypad> & Props, "paginationEnabled">>;
|
|
21
|
-
export default _default;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
|
-
import type { AnalyticsEventHandlerFn } from "@khanacademy/perseus-core";
|
|
3
|
-
import type { StyleType } from "@khanacademy/wonder-blocks-core";
|
|
4
|
-
type Props = {
|
|
5
|
-
onElementMounted?: (arg1: any) => void;
|
|
6
|
-
onDismiss?: () => void;
|
|
7
|
-
style?: StyleType;
|
|
8
|
-
useV2Keypad?: boolean;
|
|
9
|
-
onAnalyticsEvent: AnalyticsEventHandlerFn;
|
|
10
|
-
};
|
|
11
|
-
declare function KeypadSwitch(props: Props): JSX.Element;
|
|
12
|
-
export default KeypadSwitch;
|
|
@@ -1,441 +0,0 @@
|
|
|
1
|
-
import GestureStateMachine from "../gesture-state-machine";
|
|
2
|
-
|
|
3
|
-
import type {Handlers} from "../gesture-state-machine";
|
|
4
|
-
|
|
5
|
-
const swipeThresholdPx = 5;
|
|
6
|
-
const longPressWaitTimeMs = 5;
|
|
7
|
-
const holdIntervalMs = 5;
|
|
8
|
-
|
|
9
|
-
// Generates a set of handlers, to be passed to a GestureStateMachine instance,
|
|
10
|
-
// that track any callbacks, along with their arguments, by pushing to the
|
|
11
|
-
// provided buffer on call.
|
|
12
|
-
const eventTrackers = (buffer) => {
|
|
13
|
-
const handlers = {};
|
|
14
|
-
const callbackNames = [
|
|
15
|
-
"onBlur",
|
|
16
|
-
"onFocus",
|
|
17
|
-
"onTrigger",
|
|
18
|
-
"onTouchEnd",
|
|
19
|
-
"onLongPress",
|
|
20
|
-
"onSwipeChange",
|
|
21
|
-
"onSwipeEnd",
|
|
22
|
-
];
|
|
23
|
-
callbackNames.forEach((callbackName) => {
|
|
24
|
-
handlers[callbackName] = function () {
|
|
25
|
-
// eslint-disable-next-line prefer-rest-params
|
|
26
|
-
buffer.push([callbackName, ...arguments]);
|
|
27
|
-
};
|
|
28
|
-
});
|
|
29
|
-
return handlers as Handlers;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
// Arbitrary node IDs (representative of arbitrary keys) to be used in testing.
|
|
33
|
-
const NodeIds = {
|
|
34
|
-
first: "first",
|
|
35
|
-
second: "second",
|
|
36
|
-
third: "third",
|
|
37
|
-
swipeDisabled: "swipeDisabled",
|
|
38
|
-
multiPressable: "multiPressable",
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
describe("GestureStateMachine", () => {
|
|
42
|
-
let eventBuffer;
|
|
43
|
-
let stateMachine;
|
|
44
|
-
|
|
45
|
-
beforeEach(() => {
|
|
46
|
-
eventBuffer = [];
|
|
47
|
-
stateMachine = new GestureStateMachine(
|
|
48
|
-
eventTrackers(eventBuffer),
|
|
49
|
-
{
|
|
50
|
-
swipeThresholdPx,
|
|
51
|
-
longPressWaitTimeMs,
|
|
52
|
-
holdIntervalMs,
|
|
53
|
-
},
|
|
54
|
-
// @ts-expect-error TS2322
|
|
55
|
-
[NodeIds.swipeDisabled],
|
|
56
|
-
[NodeIds.multiPressable],
|
|
57
|
-
);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
const assertEvents = (expectedEvents) => {
|
|
61
|
-
expect(eventBuffer).toStrictEqual(expectedEvents);
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
it("should trigger a tap on a simple button", () => {
|
|
65
|
-
const touchId = 1;
|
|
66
|
-
|
|
67
|
-
// Trigger a touch start, followed immediately by a touch end.
|
|
68
|
-
stateMachine.onTouchStart(() => NodeIds.first, touchId, 0);
|
|
69
|
-
stateMachine.onTouchEnd(() => NodeIds.first, touchId, 0);
|
|
70
|
-
|
|
71
|
-
// Assert that we saw a focus and a touch end, in that order.
|
|
72
|
-
const expectedEvents = [
|
|
73
|
-
["onFocus", NodeIds.first],
|
|
74
|
-
["onTouchEnd", NodeIds.first],
|
|
75
|
-
];
|
|
76
|
-
assertEvents(expectedEvents);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it("should shift focus to a new button on move", () => {
|
|
80
|
-
const touchId = 1;
|
|
81
|
-
|
|
82
|
-
// Trigger a touch start on one node before moving over another node and
|
|
83
|
-
// releasing.
|
|
84
|
-
stateMachine.onTouchStart(() => NodeIds.first, touchId, 0);
|
|
85
|
-
stateMachine.onTouchMove(() => NodeIds.second, touchId, 0);
|
|
86
|
-
stateMachine.onTouchEnd(() => NodeIds.second, touchId, 0);
|
|
87
|
-
|
|
88
|
-
// Assert that we saw a focus on both nodes.
|
|
89
|
-
const expectedEvents = [
|
|
90
|
-
["onFocus", NodeIds.first],
|
|
91
|
-
["onFocus", NodeIds.second],
|
|
92
|
-
["onTouchEnd", NodeIds.second],
|
|
93
|
-
];
|
|
94
|
-
assertEvents(expectedEvents);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it("should trigger a long press on hold", () => {
|
|
98
|
-
const touchId = 1;
|
|
99
|
-
|
|
100
|
-
/// Trigger a touch start.
|
|
101
|
-
stateMachine.onTouchStart(() => NodeIds.first, touchId, 0);
|
|
102
|
-
|
|
103
|
-
// Assert that we see a focus event immediately.
|
|
104
|
-
const initialExpectedEvents = [["onFocus", NodeIds.first]];
|
|
105
|
-
assertEvents(initialExpectedEvents);
|
|
106
|
-
|
|
107
|
-
jest.advanceTimersByTime(longPressWaitTimeMs);
|
|
108
|
-
|
|
109
|
-
const expectedEventsAfterLongPress = [
|
|
110
|
-
...initialExpectedEvents,
|
|
111
|
-
["onLongPress", NodeIds.first],
|
|
112
|
-
];
|
|
113
|
-
assertEvents(expectedEventsAfterLongPress);
|
|
114
|
-
|
|
115
|
-
// Finish up the interaction.
|
|
116
|
-
stateMachine.onTouchEnd(() => NodeIds.first, touchId, 0);
|
|
117
|
-
|
|
118
|
-
// Assert that we still see a touch-end.
|
|
119
|
-
const expectedEventsAfterRelease = [
|
|
120
|
-
...expectedEventsAfterLongPress,
|
|
121
|
-
["onTouchEnd", NodeIds.first],
|
|
122
|
-
];
|
|
123
|
-
assertEvents(expectedEventsAfterRelease);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it("should trigger multiple presses on hold", () => {
|
|
127
|
-
const touchId = 1;
|
|
128
|
-
|
|
129
|
-
// Trigger a touch start on the multi-pressable node.
|
|
130
|
-
stateMachine.onTouchStart(() => NodeIds.multiPressable, touchId, 0);
|
|
131
|
-
|
|
132
|
-
// Assert that we see an immediate focus and trigger.
|
|
133
|
-
const initialExpectedEvents = [
|
|
134
|
-
["onFocus", NodeIds.multiPressable],
|
|
135
|
-
["onTrigger", NodeIds.multiPressable],
|
|
136
|
-
];
|
|
137
|
-
assertEvents(initialExpectedEvents);
|
|
138
|
-
|
|
139
|
-
jest.advanceTimersByTime(holdIntervalMs);
|
|
140
|
-
|
|
141
|
-
// Assert that we see an additional trigger after the delay.
|
|
142
|
-
const expectedEventsAfterHold = [
|
|
143
|
-
...initialExpectedEvents,
|
|
144
|
-
["onTrigger", NodeIds.multiPressable],
|
|
145
|
-
];
|
|
146
|
-
assertEvents(expectedEventsAfterHold);
|
|
147
|
-
|
|
148
|
-
// Now release, and verify that we see a blur, but no touch-end.
|
|
149
|
-
stateMachine.onTouchEnd(() => NodeIds.multiPressable, touchId, 0);
|
|
150
|
-
const expectedEventsAfterRelease = [
|
|
151
|
-
...expectedEventsAfterHold,
|
|
152
|
-
["onBlur"],
|
|
153
|
-
];
|
|
154
|
-
assertEvents(expectedEventsAfterRelease);
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it("should be robust to multiple touch starts", () => {
|
|
158
|
-
const touchId = 1;
|
|
159
|
-
|
|
160
|
-
// Trigger a touch start on the multi-pressable node twice, because
|
|
161
|
-
// the webview was acting up.
|
|
162
|
-
stateMachine.onTouchStart(() => NodeIds.multiPressable, touchId, 0);
|
|
163
|
-
stateMachine.onTouchStart(() => NodeIds.multiPressable, touchId, 0);
|
|
164
|
-
|
|
165
|
-
// Assert that we see only one set of focus and triggers.
|
|
166
|
-
const initialExpectedEvents = [
|
|
167
|
-
["onFocus", NodeIds.multiPressable],
|
|
168
|
-
["onTrigger", NodeIds.multiPressable],
|
|
169
|
-
];
|
|
170
|
-
assertEvents(initialExpectedEvents);
|
|
171
|
-
|
|
172
|
-
jest.advanceTimersByTime(holdIntervalMs);
|
|
173
|
-
|
|
174
|
-
// Assert that we see an additional trigger after the delay.
|
|
175
|
-
const expectedEventsAfterHold = [
|
|
176
|
-
...initialExpectedEvents,
|
|
177
|
-
["onTrigger", NodeIds.multiPressable],
|
|
178
|
-
];
|
|
179
|
-
assertEvents(expectedEventsAfterHold);
|
|
180
|
-
|
|
181
|
-
// Now release, and verify that we see a blur, but no touch-end.
|
|
182
|
-
stateMachine.onTouchEnd(() => NodeIds.multiPressable, touchId, 0);
|
|
183
|
-
const expectedEventsAfterRelease = [
|
|
184
|
-
...expectedEventsAfterHold,
|
|
185
|
-
["onBlur"],
|
|
186
|
-
];
|
|
187
|
-
assertEvents(expectedEventsAfterRelease);
|
|
188
|
-
|
|
189
|
-
jest.advanceTimersByTime(holdIntervalMs);
|
|
190
|
-
// Ensure the touch end cleaned it up, and that we didn't
|
|
191
|
-
// create multiple listeners.
|
|
192
|
-
assertEvents(expectedEventsAfterRelease);
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
/* Swiping. */
|
|
196
|
-
|
|
197
|
-
it("should transition to a swipe", () => {
|
|
198
|
-
const touchId = 1;
|
|
199
|
-
|
|
200
|
-
// Trigger a touch start, followed by a move past the swipe threshold.
|
|
201
|
-
const startX = 0;
|
|
202
|
-
const swipeDistancePx = swipeThresholdPx + 1;
|
|
203
|
-
stateMachine.onTouchStart(() => NodeIds.first, touchId, startX);
|
|
204
|
-
stateMachine.onTouchMove(
|
|
205
|
-
() => NodeIds.first,
|
|
206
|
-
touchId,
|
|
207
|
-
startX + swipeDistancePx,
|
|
208
|
-
true,
|
|
209
|
-
);
|
|
210
|
-
stateMachine.onTouchEnd(
|
|
211
|
-
() => NodeIds.first,
|
|
212
|
-
touchId,
|
|
213
|
-
startX + swipeDistancePx,
|
|
214
|
-
);
|
|
215
|
-
|
|
216
|
-
// Assert that the node is focused and then blurred before transitioning
|
|
217
|
-
// to a swipe.
|
|
218
|
-
const expectedEvents = [
|
|
219
|
-
["onFocus", NodeIds.first],
|
|
220
|
-
["onBlur"],
|
|
221
|
-
["onSwipeChange", swipeDistancePx],
|
|
222
|
-
["onSwipeEnd", swipeDistancePx],
|
|
223
|
-
];
|
|
224
|
-
assertEvents(expectedEvents);
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
it("should not transition to a swipe when swiping is diabled", () => {
|
|
228
|
-
const touchId = 1;
|
|
229
|
-
|
|
230
|
-
// Trigger a touch start, followed by a move past the swipe threshold.
|
|
231
|
-
const startX = 0;
|
|
232
|
-
const swipeDistancePx = swipeThresholdPx + 1;
|
|
233
|
-
stateMachine.onTouchStart(() => NodeIds.first, touchId, startX);
|
|
234
|
-
stateMachine.onTouchMove(
|
|
235
|
-
() => NodeIds.first,
|
|
236
|
-
touchId,
|
|
237
|
-
startX + swipeDistancePx,
|
|
238
|
-
false,
|
|
239
|
-
);
|
|
240
|
-
|
|
241
|
-
// Assert that the node is focused but never blurred.
|
|
242
|
-
const expectedEvents = [["onFocus", NodeIds.first]];
|
|
243
|
-
assertEvents(expectedEvents);
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
it("should not transition to a swipe on drag from a locked key", () => {
|
|
247
|
-
const touchId = 1;
|
|
248
|
-
|
|
249
|
-
// Trigger a touch start, followed by a move past the swipe threshold.
|
|
250
|
-
const startX = 0;
|
|
251
|
-
const swipeDistancePx = swipeThresholdPx + 1;
|
|
252
|
-
stateMachine.onTouchStart(() => NodeIds.swipeDisabled, touchId, startX);
|
|
253
|
-
stateMachine.onTouchMove(
|
|
254
|
-
() => NodeIds.swipeDisabled,
|
|
255
|
-
touchId,
|
|
256
|
-
startX + swipeDistancePx,
|
|
257
|
-
true,
|
|
258
|
-
);
|
|
259
|
-
|
|
260
|
-
// Assert that the node is focused but never blurred.
|
|
261
|
-
const expectedEvents = [["onFocus", NodeIds.swipeDisabled]];
|
|
262
|
-
assertEvents(expectedEvents);
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
/* Multi-touch. */
|
|
266
|
-
|
|
267
|
-
it("should respect simultaneous taps by two fingers", () => {
|
|
268
|
-
const firstTouchId = 1;
|
|
269
|
-
const secondTouchId = 2;
|
|
270
|
-
|
|
271
|
-
// Tap down on the first node, then on the second node; then release
|
|
272
|
-
// on the second, and then the first.
|
|
273
|
-
stateMachine.onTouchStart(() => NodeIds.first, firstTouchId, 0);
|
|
274
|
-
stateMachine.onTouchStart(() => NodeIds.second, secondTouchId, 0);
|
|
275
|
-
stateMachine.onTouchEnd(() => NodeIds.second, secondTouchId, 0);
|
|
276
|
-
stateMachine.onTouchEnd(() => NodeIds.first, firstTouchId, 0);
|
|
277
|
-
|
|
278
|
-
// Assert that we saw a focus and a touch end, in that order.
|
|
279
|
-
const expectedEvents = [
|
|
280
|
-
["onFocus", NodeIds.first],
|
|
281
|
-
["onFocus", NodeIds.second],
|
|
282
|
-
["onTouchEnd", NodeIds.second],
|
|
283
|
-
["onTouchEnd", NodeIds.first],
|
|
284
|
-
];
|
|
285
|
-
assertEvents(expectedEvents);
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
it("should ignore any additional touches when swiping", () => {
|
|
289
|
-
const firstTouchId = 1;
|
|
290
|
-
const secondTouchId = 2;
|
|
291
|
-
const thirdTouchId = 3;
|
|
292
|
-
|
|
293
|
-
// Tap down on the first node, then on the second node. Then use the
|
|
294
|
-
const startX = 0;
|
|
295
|
-
stateMachine.onTouchStart(() => NodeIds.first, firstTouchId, startX);
|
|
296
|
-
stateMachine.onTouchStart(() => NodeIds.second, secondTouchId, startX);
|
|
297
|
-
|
|
298
|
-
// Now, swipe with the second finger.
|
|
299
|
-
const swipeDistancePx = swipeThresholdPx + 1;
|
|
300
|
-
stateMachine.onTouchMove(
|
|
301
|
-
() => NodeIds.second,
|
|
302
|
-
secondTouchId,
|
|
303
|
-
startX + swipeDistancePx,
|
|
304
|
-
true,
|
|
305
|
-
);
|
|
306
|
-
|
|
307
|
-
const expectedEventsAfterSwipeStart = [
|
|
308
|
-
["onFocus", NodeIds.first],
|
|
309
|
-
["onFocus", NodeIds.second],
|
|
310
|
-
["onBlur"],
|
|
311
|
-
["onSwipeChange", startX + swipeDistancePx],
|
|
312
|
-
];
|
|
313
|
-
assertEvents(expectedEventsAfterSwipeStart);
|
|
314
|
-
|
|
315
|
-
// Send some touch events via the non-swiping but active touch,
|
|
316
|
-
// simulating moving the finger over another node, and even moving it
|
|
317
|
-
// enough to swipe, before releasing.
|
|
318
|
-
stateMachine.onTouchMove(() => NodeIds.first, firstTouchId, 0);
|
|
319
|
-
stateMachine.onTouchMove(() => NodeIds.third, firstTouchId, 0);
|
|
320
|
-
stateMachine.onTouchMove(
|
|
321
|
-
() => NodeIds.third,
|
|
322
|
-
firstTouchId,
|
|
323
|
-
startX + swipeDistancePx,
|
|
324
|
-
true,
|
|
325
|
-
);
|
|
326
|
-
stateMachine.onTouchEnd(() => NodeIds.third, firstTouchId, 0);
|
|
327
|
-
|
|
328
|
-
// Assert that we see no new events.
|
|
329
|
-
assertEvents(expectedEventsAfterSwipeStart);
|
|
330
|
-
|
|
331
|
-
// Start a new touch event, over any node.
|
|
332
|
-
stateMachine.onTouchStart(() => NodeIds.first, thirdTouchId, 0);
|
|
333
|
-
|
|
334
|
-
// Assert that we still see no new events.
|
|
335
|
-
assertEvents(expectedEventsAfterSwipeStart);
|
|
336
|
-
|
|
337
|
-
// Finally, release with the second finger, which is mid-swipe.
|
|
338
|
-
stateMachine.onTouchEnd(
|
|
339
|
-
() => NodeIds.second,
|
|
340
|
-
secondTouchId,
|
|
341
|
-
startX + swipeDistancePx,
|
|
342
|
-
);
|
|
343
|
-
const expectedEventsAfterSwipeEnd = [
|
|
344
|
-
...expectedEventsAfterSwipeStart,
|
|
345
|
-
["onSwipeEnd", startX + swipeDistancePx],
|
|
346
|
-
];
|
|
347
|
-
assertEvents(expectedEventsAfterSwipeEnd);
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
it("should track swipe displacement on a per-finger basis", () => {
|
|
351
|
-
const firstTouchId = 1;
|
|
352
|
-
const firstTouchStartX = 15;
|
|
353
|
-
const secondTouchId = 2;
|
|
354
|
-
const secondTouchStartX = firstTouchStartX + 2 * swipeThresholdPx;
|
|
355
|
-
|
|
356
|
-
// Kick off two separate touch gestures at positions separated by more
|
|
357
|
-
// than the swipe displacement.
|
|
358
|
-
stateMachine.onTouchStart(
|
|
359
|
-
() => NodeIds.first,
|
|
360
|
-
firstTouchId,
|
|
361
|
-
firstTouchStartX,
|
|
362
|
-
);
|
|
363
|
-
stateMachine.onTouchStart(
|
|
364
|
-
() => NodeIds.second,
|
|
365
|
-
secondTouchId,
|
|
366
|
-
secondTouchStartX,
|
|
367
|
-
);
|
|
368
|
-
|
|
369
|
-
// Move less than the swipe threshold with both fingers.
|
|
370
|
-
stateMachine.onTouchMove(
|
|
371
|
-
() => NodeIds.first,
|
|
372
|
-
firstTouchId,
|
|
373
|
-
firstTouchStartX + swipeThresholdPx - 1,
|
|
374
|
-
true,
|
|
375
|
-
);
|
|
376
|
-
stateMachine.onTouchMove(
|
|
377
|
-
() => NodeIds.second,
|
|
378
|
-
secondTouchId,
|
|
379
|
-
secondTouchStartX + swipeThresholdPx - 1,
|
|
380
|
-
true,
|
|
381
|
-
);
|
|
382
|
-
|
|
383
|
-
// Assert that we haven't started swiping--all we've done is focused the
|
|
384
|
-
// various nodes.
|
|
385
|
-
const initialExpectedEvents = [
|
|
386
|
-
["onFocus", NodeIds.first],
|
|
387
|
-
["onFocus", NodeIds.second],
|
|
388
|
-
];
|
|
389
|
-
assertEvents(initialExpectedEvents);
|
|
390
|
-
|
|
391
|
-
// Swipe past the threshold with one finger.
|
|
392
|
-
const swipeDistancePx = swipeThresholdPx + 1;
|
|
393
|
-
stateMachine.onTouchMove(
|
|
394
|
-
() => NodeIds.first,
|
|
395
|
-
firstTouchId,
|
|
396
|
-
firstTouchStartX + swipeDistancePx,
|
|
397
|
-
true,
|
|
398
|
-
);
|
|
399
|
-
const expectedEventsAfterSwipeStart = [
|
|
400
|
-
...initialExpectedEvents,
|
|
401
|
-
["onBlur"],
|
|
402
|
-
["onSwipeChange", swipeDistancePx],
|
|
403
|
-
];
|
|
404
|
-
assertEvents(expectedEventsAfterSwipeStart);
|
|
405
|
-
});
|
|
406
|
-
|
|
407
|
-
it("should be robust to extraneous fingers", () => {
|
|
408
|
-
const firstTouchId = 1;
|
|
409
|
-
const firstTouchStartX = 15;
|
|
410
|
-
const secondTouchId = 2;
|
|
411
|
-
const secondTouchStartX = firstTouchStartX + 2 * swipeThresholdPx;
|
|
412
|
-
|
|
413
|
-
// The first finger initiates a gesture, but the second finger starts
|
|
414
|
-
// elsewhere on the screen and doesn't register a start...
|
|
415
|
-
stateMachine.onTouchStart(
|
|
416
|
-
() => NodeIds.first,
|
|
417
|
-
firstTouchId,
|
|
418
|
-
firstTouchStartX,
|
|
419
|
-
);
|
|
420
|
-
|
|
421
|
-
// Move the first finger, but less than the swipe threshold, and then
|
|
422
|
-
// start showing move events from the second finger (as it slides into
|
|
423
|
-
// the components we care about on screen)
|
|
424
|
-
stateMachine.onTouchMove(
|
|
425
|
-
() => NodeIds.first,
|
|
426
|
-
firstTouchId,
|
|
427
|
-
firstTouchStartX + swipeThresholdPx - 1,
|
|
428
|
-
true,
|
|
429
|
-
);
|
|
430
|
-
stateMachine.onTouchMove(
|
|
431
|
-
() => NodeIds.second,
|
|
432
|
-
secondTouchId,
|
|
433
|
-
secondTouchStartX,
|
|
434
|
-
true,
|
|
435
|
-
);
|
|
436
|
-
|
|
437
|
-
// Assert we've started focusing but haven't blown up.
|
|
438
|
-
const initialExpectedEvents = [["onFocus", NodeIds.first]];
|
|
439
|
-
assertEvents(initialExpectedEvents);
|
|
440
|
-
});
|
|
441
|
-
});
|