@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.
Files changed (138) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/components/keypad/index.d.ts +1 -1
  3. package/dist/components/keypad/mobile-keypad-internals.d.ts +49 -0
  4. package/dist/components/keypad/mobile-keypad.d.ts +4 -48
  5. package/dist/es/index.js +168 -4740
  6. package/dist/es/index.js.map +1 -1
  7. package/dist/index.d.ts +1 -1
  8. package/dist/index.js +166 -4722
  9. package/dist/index.js.map +1 -1
  10. package/package.json +1 -1
  11. package/src/components/__tests__/integration.test.tsx +2 -3
  12. package/src/components/keypad/__tests__/mobile-keypad.test.tsx +8 -8
  13. package/src/components/keypad/index.tsx +1 -1
  14. package/src/components/keypad/mobile-keypad-internals.tsx +240 -0
  15. package/src/components/keypad/mobile-keypad.tsx +21 -234
  16. package/src/full-mobile-input.stories.tsx +0 -1
  17. package/src/index.ts +1 -1
  18. package/tsconfig-build.tsbuildinfo +1 -1
  19. package/dist/components/keypad-legacy/compute-layout-parameters.d.ts +0 -28
  20. package/dist/components/keypad-legacy/corner-decal.d.ts +0 -12
  21. package/dist/components/keypad-legacy/echo-manager.d.ts +0 -17
  22. package/dist/components/keypad-legacy/empty-keypad-button.d.ts +0 -13
  23. package/dist/components/keypad-legacy/expression-keypad.d.ts +0 -21
  24. package/dist/components/keypad-legacy/fraction-keypad.d.ts +0 -21
  25. package/dist/components/keypad-legacy/gesture-manager.d.ts +0 -86
  26. package/dist/components/keypad-legacy/gesture-state-machine.d.ts +0 -105
  27. package/dist/components/keypad-legacy/icon.d.ts +0 -15
  28. package/dist/components/keypad-legacy/index.d.ts +0 -1
  29. package/dist/components/keypad-legacy/keypad-button.d.ts +0 -53
  30. package/dist/components/keypad-legacy/keypad-container.d.ts +0 -41
  31. package/dist/components/keypad-legacy/keypad.d.ts +0 -31
  32. package/dist/components/keypad-legacy/many-keypad-button.d.ts +0 -15
  33. package/dist/components/keypad-legacy/math-icon.d.ts +0 -16
  34. package/dist/components/keypad-legacy/multi-symbol-grid.d.ts +0 -14
  35. package/dist/components/keypad-legacy/multi-symbol-popover.d.ts +0 -12
  36. package/dist/components/keypad-legacy/navigation-pad.d.ts +0 -14
  37. package/dist/components/keypad-legacy/node-manager.d.ts +0 -49
  38. package/dist/components/keypad-legacy/popover-manager.d.ts +0 -13
  39. package/dist/components/keypad-legacy/popover-state-machine.d.ts +0 -68
  40. package/dist/components/keypad-legacy/provided-keypad.d.ts +0 -28
  41. package/dist/components/keypad-legacy/store/actions.d.ts +0 -55
  42. package/dist/components/keypad-legacy/store/echo-reducer.d.ts +0 -4
  43. package/dist/components/keypad-legacy/store/index.d.ts +0 -9
  44. package/dist/components/keypad-legacy/store/input-reducer.d.ts +0 -4
  45. package/dist/components/keypad-legacy/store/keypad-reducer.d.ts +0 -4
  46. package/dist/components/keypad-legacy/store/layout-reducer.d.ts +0 -4
  47. package/dist/components/keypad-legacy/store/shared.d.ts +0 -7
  48. package/dist/components/keypad-legacy/store/types.d.ts +0 -47
  49. package/dist/components/keypad-legacy/styles.d.ts +0 -5
  50. package/dist/components/keypad-legacy/svg-icon.d.ts +0 -12
  51. package/dist/components/keypad-legacy/text-icon.d.ts +0 -13
  52. package/dist/components/keypad-legacy/touchable-keypad-button.d.ts +0 -37
  53. package/dist/components/keypad-legacy/two-page-keypad.d.ts +0 -21
  54. package/dist/components/keypad-legacy/z-indexes.d.ts +0 -7
  55. package/dist/components/keypad-switch.d.ts +0 -12
  56. package/src/components/keypad-legacy/__tests__/gesture-state-machine.test.ts +0 -441
  57. package/src/components/keypad-legacy/__tests__/node-manager.test.ts +0 -89
  58. package/src/components/keypad-legacy/compute-layout-parameters.ts +0 -205
  59. package/src/components/keypad-legacy/corner-decal.tsx +0 -56
  60. package/src/components/keypad-legacy/echo-manager.tsx +0 -152
  61. package/src/components/keypad-legacy/empty-keypad-button.tsx +0 -58
  62. package/src/components/keypad-legacy/expression-keypad.tsx +0 -315
  63. package/src/components/keypad-legacy/fraction-keypad.tsx +0 -180
  64. package/src/components/keypad-legacy/gesture-manager.ts +0 -255
  65. package/src/components/keypad-legacy/gesture-state-machine.ts +0 -329
  66. package/src/components/keypad-legacy/icon.tsx +0 -72
  67. package/src/components/keypad-legacy/iconography/arrow.js +0 -22
  68. package/src/components/keypad-legacy/iconography/backspace.js +0 -29
  69. package/src/components/keypad-legacy/iconography/cdot.js +0 -29
  70. package/src/components/keypad-legacy/iconography/cos.js +0 -30
  71. package/src/components/keypad-legacy/iconography/cube-root.js +0 -36
  72. package/src/components/keypad-legacy/iconography/dismiss.js +0 -25
  73. package/src/components/keypad-legacy/iconography/divide.js +0 -34
  74. package/src/components/keypad-legacy/iconography/down.js +0 -16
  75. package/src/components/keypad-legacy/iconography/equal.js +0 -33
  76. package/src/components/keypad-legacy/iconography/exp-2.js +0 -29
  77. package/src/components/keypad-legacy/iconography/exp-3.js +0 -29
  78. package/src/components/keypad-legacy/iconography/exp.js +0 -29
  79. package/src/components/keypad-legacy/iconography/frac.js +0 -44
  80. package/src/components/keypad-legacy/iconography/geq.js +0 -33
  81. package/src/components/keypad-legacy/iconography/gt.js +0 -33
  82. package/src/components/keypad-legacy/iconography/index.js +0 -45
  83. package/src/components/keypad-legacy/iconography/jump-into-numerator.js +0 -41
  84. package/src/components/keypad-legacy/iconography/jump-out-base.js +0 -30
  85. package/src/components/keypad-legacy/iconography/jump-out-denominator.js +0 -41
  86. package/src/components/keypad-legacy/iconography/jump-out-exponent.js +0 -30
  87. package/src/components/keypad-legacy/iconography/jump-out-numerator.js +0 -41
  88. package/src/components/keypad-legacy/iconography/jump-out-parentheses.js +0 -33
  89. package/src/components/keypad-legacy/iconography/left-paren.js +0 -33
  90. package/src/components/keypad-legacy/iconography/left.js +0 -16
  91. package/src/components/keypad-legacy/iconography/leq.js +0 -33
  92. package/src/components/keypad-legacy/iconography/ln.js +0 -29
  93. package/src/components/keypad-legacy/iconography/log-n.js +0 -29
  94. package/src/components/keypad-legacy/iconography/log.js +0 -29
  95. package/src/components/keypad-legacy/iconography/lt.js +0 -33
  96. package/src/components/keypad-legacy/iconography/minus.js +0 -32
  97. package/src/components/keypad-legacy/iconography/neq.js +0 -33
  98. package/src/components/keypad-legacy/iconography/parens.js +0 -33
  99. package/src/components/keypad-legacy/iconography/percent.js +0 -49
  100. package/src/components/keypad-legacy/iconography/period.js +0 -26
  101. package/src/components/keypad-legacy/iconography/plus.js +0 -32
  102. package/src/components/keypad-legacy/iconography/radical.js +0 -36
  103. package/src/components/keypad-legacy/iconography/right-paren.js +0 -33
  104. package/src/components/keypad-legacy/iconography/right.js +0 -16
  105. package/src/components/keypad-legacy/iconography/sin.js +0 -30
  106. package/src/components/keypad-legacy/iconography/sqrt.js +0 -32
  107. package/src/components/keypad-legacy/iconography/tan.js +0 -30
  108. package/src/components/keypad-legacy/iconography/times.js +0 -33
  109. package/src/components/keypad-legacy/iconography/up.js +0 -16
  110. package/src/components/keypad-legacy/index.ts +0 -1
  111. package/src/components/keypad-legacy/keypad-button.tsx +0 -368
  112. package/src/components/keypad-legacy/keypad-container.tsx +0 -358
  113. package/src/components/keypad-legacy/keypad.tsx +0 -162
  114. package/src/components/keypad-legacy/many-keypad-button.tsx +0 -54
  115. package/src/components/keypad-legacy/math-icon.tsx +0 -66
  116. package/src/components/keypad-legacy/multi-symbol-grid.tsx +0 -182
  117. package/src/components/keypad-legacy/multi-symbol-popover.tsx +0 -58
  118. package/src/components/keypad-legacy/navigation-pad.tsx +0 -140
  119. package/src/components/keypad-legacy/node-manager.ts +0 -133
  120. package/src/components/keypad-legacy/popover-manager.tsx +0 -73
  121. package/src/components/keypad-legacy/popover-state-machine.ts +0 -184
  122. package/src/components/keypad-legacy/provided-keypad.tsx +0 -136
  123. package/src/components/keypad-legacy/store/actions.ts +0 -155
  124. package/src/components/keypad-legacy/store/echo-reducer.ts +0 -57
  125. package/src/components/keypad-legacy/store/index.ts +0 -110
  126. package/src/components/keypad-legacy/store/input-reducer.ts +0 -55
  127. package/src/components/keypad-legacy/store/keypad-reducer.ts +0 -58
  128. package/src/components/keypad-legacy/store/layout-reducer.test.ts +0 -171
  129. package/src/components/keypad-legacy/store/layout-reducer.ts +0 -129
  130. package/src/components/keypad-legacy/store/shared.ts +0 -12
  131. package/src/components/keypad-legacy/store/types.ts +0 -78
  132. package/src/components/keypad-legacy/styles.ts +0 -38
  133. package/src/components/keypad-legacy/svg-icon.tsx +0 -24
  134. package/src/components/keypad-legacy/text-icon.tsx +0 -53
  135. package/src/components/keypad-legacy/touchable-keypad-button.tsx +0 -163
  136. package/src/components/keypad-legacy/two-page-keypad.tsx +0 -115
  137. package/src/components/keypad-legacy/z-indexes.ts +0 -8
  138. 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,5 +0,0 @@
1
- /**
2
- * Common styles shared across components.
3
- */
4
- declare const _default: any;
5
- export default _default;
@@ -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,7 +0,0 @@
1
- /**
2
- * This file contains all of the z-index values used throughout the math-input
3
- * component and its children.
4
- */
5
- export declare const popover = 1;
6
- export declare const echo = 2;
7
- export declare const keypad = 1060;
@@ -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
- });