@khanacademy/wonder-blocks-clickable 2.4.4 → 2.4.6
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 +35 -0
- package/dist/components/clickable-behavior.d.ts +248 -0
- package/dist/components/clickable-behavior.js.flow +296 -0
- package/dist/components/clickable.d.ts +150 -0
- package/dist/components/clickable.js.flow +176 -0
- package/dist/es/index.js +147 -147
- package/dist/index.d.ts +7 -0
- package/dist/index.js +169 -171
- package/dist/index.js.flow +18 -2
- package/dist/util/get-clickable-behavior.d.ts +25 -0
- package/dist/util/get-clickable-behavior.js.flow +19 -0
- package/dist/util/is-client-side-url.d.ts +7 -0
- package/dist/util/is-client-side-url.js.flow +14 -0
- package/package.json +5 -5
- package/src/components/__tests__/{clickable-behavior.test.js → clickable-behavior.test.tsx} +140 -84
- package/src/components/__tests__/{clickable.test.js → clickable.test.tsx} +28 -27
- package/src/components/{clickable-behavior.js → clickable-behavior.ts} +82 -104
- package/src/components/{clickable.js → clickable.tsx} +111 -168
- package/src/{index.js → index.ts} +5 -6
- package/src/util/__tests__/{get-clickable-behavior.test.js → get-clickable-behavior.test.tsx} +2 -3
- package/src/util/__tests__/{is-client-side-url.js.test.js → is-client-side-url.js.test.ts} +3 -4
- package/src/util/{get-clickable-behavior.js → get-clickable-behavior.ts} +11 -5
- package/src/util/{is-client-side-url.js → is-client-side-url.ts} +0 -1
- package/tsconfig.json +12 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/src/components/__docs__/accessibility.stories.mdx +0 -152
- package/src/components/__docs__/clickable-behavior.argtypes.js +0 -64
- package/src/components/__docs__/clickable-behavior.stories.js +0 -178
- package/src/components/__docs__/clickable.argtypes.js +0 -237
- package/src/components/__docs__/clickable.stories.js +0 -307
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
// @flow
|
|
2
1
|
import * as React from "react";
|
|
3
2
|
import {MemoryRouter, Route, Switch} from "react-router-dom";
|
|
4
3
|
import {render, screen, fireEvent, waitFor} from "@testing-library/react";
|
|
5
4
|
import userEvent from "@testing-library/user-event";
|
|
6
5
|
|
|
7
6
|
import {View} from "@khanacademy/wonder-blocks-core";
|
|
8
|
-
import Clickable from "../clickable
|
|
7
|
+
import Clickable from "../clickable";
|
|
9
8
|
|
|
10
9
|
describe("Clickable", () => {
|
|
11
10
|
beforeEach(() => {
|
|
11
|
+
// @ts-expect-error [FEI-5019] - TS2790 - The operand of a 'delete' operator must be optional.
|
|
12
12
|
delete window.location;
|
|
13
|
+
// @ts-expect-error [FEI-5019] - TS2740 - Type '{ assign: Mock<any, any, any>; }' is missing the following properties from type 'Location': ancestorOrigins, hash, host, hostname, and 8 more.
|
|
13
14
|
window.location = {assign: jest.fn()};
|
|
14
15
|
});
|
|
15
16
|
|
|
@@ -19,7 +20,7 @@ describe("Clickable", () => {
|
|
|
19
20
|
<MemoryRouter>
|
|
20
21
|
<View>
|
|
21
22
|
<Clickable testId="button" href="/foo">
|
|
22
|
-
{(eventState) => <h1>Click Me!</h1>}
|
|
23
|
+
{(eventState: any) => <h1>Click Me!</h1>}
|
|
23
24
|
</Clickable>
|
|
24
25
|
<Switch>
|
|
25
26
|
<Route path="/foo">
|
|
@@ -43,7 +44,7 @@ describe("Clickable", () => {
|
|
|
43
44
|
<MemoryRouter>
|
|
44
45
|
<View>
|
|
45
46
|
<Clickable testId="button" href="/unknown">
|
|
46
|
-
{(eventState) => <h1>Click Me!</h1>}
|
|
47
|
+
{(eventState: any) => <h1>Click Me!</h1>}
|
|
47
48
|
</Clickable>
|
|
48
49
|
<Switch>
|
|
49
50
|
<Route path="/foo">
|
|
@@ -67,7 +68,7 @@ describe("Clickable", () => {
|
|
|
67
68
|
<MemoryRouter>
|
|
68
69
|
<View>
|
|
69
70
|
<Clickable testId="button" href="/foo" skipClientNav>
|
|
70
|
-
{(eventState) => <h1>Click Me!</h1>}
|
|
71
|
+
{(eventState: any) => <h1>Click Me!</h1>}
|
|
71
72
|
</Clickable>
|
|
72
73
|
<Switch>
|
|
73
74
|
<Route path="/foo">
|
|
@@ -91,7 +92,7 @@ describe("Clickable", () => {
|
|
|
91
92
|
<MemoryRouter>
|
|
92
93
|
<View>
|
|
93
94
|
<Clickable testId="button" href="/foo" disabled={true}>
|
|
94
|
-
{(eventState) => <h1>Click Me!</h1>}
|
|
95
|
+
{(eventState: any) => <h1>Click Me!</h1>}
|
|
95
96
|
</Clickable>
|
|
96
97
|
<Switch>
|
|
97
98
|
<Route path="/foo">
|
|
@@ -113,7 +114,7 @@ describe("Clickable", () => {
|
|
|
113
114
|
// Arrange, Act
|
|
114
115
|
render(
|
|
115
116
|
<Clickable testId="button" href="/foo" skipClientNav={true}>
|
|
116
|
-
{(eventState) => <h1>Click Me!</h1>}
|
|
117
|
+
{(eventState: any) => <h1>Click Me!</h1>}
|
|
117
118
|
</Clickable>,
|
|
118
119
|
);
|
|
119
120
|
|
|
@@ -127,7 +128,7 @@ describe("Clickable", () => {
|
|
|
127
128
|
// Arrange
|
|
128
129
|
render(
|
|
129
130
|
<Clickable testId="button" href="/foo" skipClientNav={true}>
|
|
130
|
-
{(eventState) => <h1>Click Me!</h1>}
|
|
131
|
+
{(eventState: any) => <h1>Click Me!</h1>}
|
|
131
132
|
</Clickable>,
|
|
132
133
|
);
|
|
133
134
|
|
|
@@ -149,7 +150,7 @@ describe("Clickable", () => {
|
|
|
149
150
|
<Clickable
|
|
150
151
|
testId="button"
|
|
151
152
|
href="/foo"
|
|
152
|
-
beforeNav={(
|
|
153
|
+
beforeNav={() => Promise.reject()}
|
|
153
154
|
>
|
|
154
155
|
{() => <span>Click me!</span>}
|
|
155
156
|
</Clickable>
|
|
@@ -178,7 +179,7 @@ describe("Clickable", () => {
|
|
|
178
179
|
<Clickable
|
|
179
180
|
testId="button"
|
|
180
181
|
href="/foo"
|
|
181
|
-
beforeNav={(
|
|
182
|
+
beforeNav={() => Promise.reject()}
|
|
182
183
|
safeWithNav={safeWithNavMock}
|
|
183
184
|
>
|
|
184
185
|
{() => <span>Click me!</span>}
|
|
@@ -207,7 +208,7 @@ describe("Clickable", () => {
|
|
|
207
208
|
<Clickable
|
|
208
209
|
testId="button"
|
|
209
210
|
href="/foo"
|
|
210
|
-
beforeNav={(
|
|
211
|
+
beforeNav={() => Promise.resolve()}
|
|
211
212
|
>
|
|
212
213
|
{() => <span>Click me!</span>}
|
|
213
214
|
</Clickable>
|
|
@@ -238,7 +239,7 @@ describe("Clickable", () => {
|
|
|
238
239
|
<Clickable
|
|
239
240
|
testId="button"
|
|
240
241
|
href="/foo"
|
|
241
|
-
beforeNav={(
|
|
242
|
+
beforeNav={() => Promise.resolve()}
|
|
242
243
|
safeWithNav={safeWithNavMock}
|
|
243
244
|
>
|
|
244
245
|
{() => <span>Click me!</span>}
|
|
@@ -269,7 +270,7 @@ describe("Clickable", () => {
|
|
|
269
270
|
<Clickable
|
|
270
271
|
testId="button"
|
|
271
272
|
href="/foo"
|
|
272
|
-
safeWithNav={(
|
|
273
|
+
safeWithNav={() => Promise.resolve()}
|
|
273
274
|
skipClientNav={true}
|
|
274
275
|
>
|
|
275
276
|
{() => <h1>Click me!</h1>}
|
|
@@ -300,8 +301,8 @@ describe("Clickable", () => {
|
|
|
300
301
|
<Clickable
|
|
301
302
|
testId="button"
|
|
302
303
|
href="/foo"
|
|
303
|
-
beforeNav={(
|
|
304
|
-
safeWithNav={(
|
|
304
|
+
beforeNav={() => Promise.resolve()}
|
|
305
|
+
safeWithNav={() => Promise.resolve()}
|
|
305
306
|
skipClientNav={true}
|
|
306
307
|
>
|
|
307
308
|
{() => <h1>Click me!</h1>}
|
|
@@ -332,7 +333,7 @@ describe("Clickable", () => {
|
|
|
332
333
|
<Clickable
|
|
333
334
|
testId="button"
|
|
334
335
|
href="/foo"
|
|
335
|
-
safeWithNav={(
|
|
336
|
+
safeWithNav={() => Promise.reject()}
|
|
336
337
|
skipClientNav={true}
|
|
337
338
|
>
|
|
338
339
|
{() => <h1>Click me!</h1>}
|
|
@@ -432,7 +433,7 @@ describe("Clickable", () => {
|
|
|
432
433
|
// Act
|
|
433
434
|
render(
|
|
434
435
|
<Clickable testId="clickable-button" disabled={true}>
|
|
435
|
-
{(eventState) => <h1>Click Me!</h1>}
|
|
436
|
+
{(eventState: any) => <h1>Click Me!</h1>}
|
|
436
437
|
</Clickable>,
|
|
437
438
|
);
|
|
438
439
|
|
|
@@ -451,7 +452,7 @@ describe("Clickable", () => {
|
|
|
451
452
|
testId="clickable-button"
|
|
452
453
|
aria-label="clickable-button-aria-label"
|
|
453
454
|
>
|
|
454
|
-
{(eventState) => <h1>Click Me!</h1>}
|
|
455
|
+
{(eventState: any) => <h1>Click Me!</h1>}
|
|
455
456
|
</Clickable>,
|
|
456
457
|
);
|
|
457
458
|
|
|
@@ -470,7 +471,7 @@ describe("Clickable", () => {
|
|
|
470
471
|
// Act
|
|
471
472
|
render(
|
|
472
473
|
<Clickable testId="clickable-button">
|
|
473
|
-
{(eventState) => <h1>Click Me!</h1>}
|
|
474
|
+
{(eventState: any) => <h1>Click Me!</h1>}
|
|
474
475
|
</Clickable>,
|
|
475
476
|
);
|
|
476
477
|
|
|
@@ -486,7 +487,7 @@ describe("Clickable", () => {
|
|
|
486
487
|
<div>
|
|
487
488
|
<button>First focusable button</button>
|
|
488
489
|
<Clickable testId="clickable-button" disabled={true}>
|
|
489
|
-
{(eventState) => <h1>Click Me!</h1>}
|
|
490
|
+
{(eventState: any) => <h1>Click Me!</h1>}
|
|
490
491
|
</Clickable>
|
|
491
492
|
</div>,
|
|
492
493
|
);
|
|
@@ -513,17 +514,17 @@ describe("Clickable", () => {
|
|
|
513
514
|
const ClickableWrapper = ({
|
|
514
515
|
children,
|
|
515
516
|
...restProps
|
|
516
|
-
}: {
|
|
517
|
-
children: React.
|
|
518
|
-
onKeyDown?: (e:
|
|
519
|
-
onKeyUp?: (e:
|
|
520
|
-
|
|
517
|
+
}: {
|
|
518
|
+
children: React.ReactNode;
|
|
519
|
+
onKeyDown?: (e: React.KeyboardEvent) => unknown;
|
|
520
|
+
onKeyUp?: (e: React.KeyboardEvent) => unknown;
|
|
521
|
+
}) => {
|
|
521
522
|
return <Clickable {...restProps}>{() => children}</Clickable>;
|
|
522
523
|
};
|
|
523
524
|
|
|
524
525
|
test("onKeyDown", () => {
|
|
525
526
|
// Arrange
|
|
526
|
-
let keyCode;
|
|
527
|
+
let keyCode: any;
|
|
527
528
|
render(
|
|
528
529
|
<ClickableWrapper onKeyDown={(e) => (keyCode = e.keyCode)}>
|
|
529
530
|
Click me!
|
|
@@ -540,7 +541,7 @@ describe("Clickable", () => {
|
|
|
540
541
|
|
|
541
542
|
test("onKeyUp", () => {
|
|
542
543
|
// Arrange
|
|
543
|
-
let keyCode;
|
|
544
|
+
let keyCode: any;
|
|
544
545
|
render(
|
|
545
546
|
<ClickableWrapper onKeyUp={(e) => (keyCode = e.keyCode)}>
|
|
546
547
|
Click me!
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// @flow
|
|
2
1
|
import * as React from "react";
|
|
3
2
|
|
|
4
3
|
// NOTE: Potentially add to this as more cases come up.
|
|
@@ -13,7 +12,7 @@ export type ClickableRole =
|
|
|
13
12
|
| "menu"
|
|
14
13
|
| "tab";
|
|
15
14
|
|
|
16
|
-
const getAppropriateTriggersForRole = (role
|
|
15
|
+
const getAppropriateTriggersForRole = (role?: ClickableRole | null) => {
|
|
17
16
|
switch (role) {
|
|
18
17
|
// Triggers on ENTER, but not SPACE
|
|
19
18
|
case "link":
|
|
@@ -42,7 +41,8 @@ const getAppropriateTriggersForRole = (role: ?ClickableRole) => {
|
|
|
42
41
|
}
|
|
43
42
|
};
|
|
44
43
|
|
|
45
|
-
|
|
44
|
+
// TODO(FEI-5000): Convert back to conditional props after TS migration is complete.
|
|
45
|
+
type Props = {
|
|
46
46
|
/**
|
|
47
47
|
* A function that returns the a React `Element`.
|
|
48
48
|
*
|
|
@@ -52,16 +52,14 @@ type CommonProps = {|
|
|
|
52
52
|
children: (
|
|
53
53
|
state: ClickableState,
|
|
54
54
|
childrenProps: ChildrenProps,
|
|
55
|
-
) => React.
|
|
56
|
-
|
|
55
|
+
) => React.ReactElement;
|
|
57
56
|
/**
|
|
58
57
|
* Whether the component is disabled.
|
|
59
58
|
*
|
|
60
59
|
* If the component is disabled, this component will return handlers
|
|
61
60
|
* that do nothing.
|
|
62
61
|
*/
|
|
63
|
-
disabled: boolean
|
|
64
|
-
|
|
62
|
+
disabled: boolean;
|
|
65
63
|
/**
|
|
66
64
|
* A URL.
|
|
67
65
|
*
|
|
@@ -71,90 +69,97 @@ type CommonProps = {|
|
|
|
71
69
|
* press would also navigate to this location. See the triggerOnEnter and
|
|
72
70
|
* triggerOnSpace props for more details.
|
|
73
71
|
*/
|
|
74
|
-
href?: string
|
|
75
|
-
|
|
72
|
+
href?: string;
|
|
76
73
|
/**
|
|
77
74
|
* This should only be used by button.js.
|
|
78
75
|
*/
|
|
79
|
-
type?: "submit"
|
|
80
|
-
|
|
76
|
+
type?: "submit";
|
|
81
77
|
/**
|
|
82
78
|
* Specifies the type of relationship between the current document and the
|
|
83
79
|
* linked document. Should only be used when `href` is specified. This
|
|
84
80
|
* defaults to "noopener noreferrer" when `target="_blank"`, but can be
|
|
85
81
|
* overridden by setting this prop to something else.
|
|
86
82
|
*/
|
|
87
|
-
rel?: string
|
|
88
|
-
|
|
89
|
-
skipClientNav?: boolean,
|
|
90
|
-
|
|
83
|
+
rel?: string;
|
|
84
|
+
skipClientNav?: boolean;
|
|
91
85
|
/**
|
|
92
86
|
* Used to indicate the tab order of an element.
|
|
93
87
|
* Use 0 to make an element focusable, and use -1 to make an
|
|
94
88
|
* element non-focusable via keyboard navigation.
|
|
95
89
|
*/
|
|
96
|
-
tabIndex?: number
|
|
97
|
-
|
|
90
|
+
tabIndex?: number;
|
|
98
91
|
/**
|
|
99
92
|
* A function to be executed `onclick`.
|
|
100
93
|
*/
|
|
101
|
-
onClick?: (e: SyntheticEvent
|
|
102
|
-
|
|
94
|
+
onClick?: (e: React.SyntheticEvent) => unknown;
|
|
103
95
|
/**
|
|
104
96
|
* Run async code in the background while client-side navigating. If the
|
|
105
97
|
* browser does a full page load navigation, the callback promise must be
|
|
106
98
|
* settled before the navigation will occur. Errors are ignored so that
|
|
107
99
|
* navigation is guaranteed to succeed.
|
|
108
100
|
*/
|
|
109
|
-
safeWithNav?: () => Promise<
|
|
110
|
-
|
|
101
|
+
safeWithNav?: () => Promise<unknown>;
|
|
111
102
|
/**
|
|
112
103
|
* Passed in by withRouter HOC.
|
|
113
104
|
* @ignore
|
|
114
105
|
*/
|
|
115
|
-
history?: any
|
|
116
|
-
|
|
106
|
+
history?: any;
|
|
117
107
|
/**
|
|
118
108
|
* A role that encapsulates how the clickable component should behave, which
|
|
119
109
|
* affects which keyboard actions trigger the component. For example, a
|
|
120
110
|
* component with role="button" should be able to be clicked with both the
|
|
121
111
|
* enter and space keys.
|
|
122
112
|
*/
|
|
123
|
-
role?: ClickableRole
|
|
124
|
-
|
|
113
|
+
role?: ClickableRole;
|
|
125
114
|
/**
|
|
126
115
|
* Respond to raw "keydown" event.
|
|
127
116
|
*/
|
|
128
|
-
onKeyDown?: (e:
|
|
129
|
-
|
|
117
|
+
onKeyDown?: (e: React.KeyboardEvent) => unknown;
|
|
130
118
|
/**
|
|
131
119
|
* Respond to raw "keyup" event.
|
|
132
120
|
*/
|
|
133
|
-
onKeyUp?: (e:
|
|
134
|
-
|
|
121
|
+
onKeyUp?: (e: React.KeyboardEvent) => unknown;
|
|
122
|
+
/**
|
|
123
|
+
* A target destination window for a link to open in. Should only be used
|
|
124
|
+
* when `href` is specified.
|
|
125
|
+
*/
|
|
126
|
+
// TODO(WB-1262): only allow this prop when `href` is also set.
|
|
127
|
+
target?: "_blank";
|
|
128
|
+
/**
|
|
129
|
+
* Run async code before navigating to the URL passed to `href`. If the
|
|
130
|
+
* promise returned rejects then navigation will not occur.
|
|
131
|
+
*
|
|
132
|
+
* If both safeWithNav and beforeNav are provided, beforeNav will be run
|
|
133
|
+
* first and safeWithNav will only be run if beforeNav does not reject.
|
|
134
|
+
*
|
|
135
|
+
* WARNING: Using this with `target="_blank"` will trigger built-in popup
|
|
136
|
+
* blockers in Firefox and Safari. This is because we do navigation
|
|
137
|
+
* programmatically and `beforeNav` causes a delay which means that the
|
|
138
|
+
* browser can't make a directly link between a user action and the
|
|
139
|
+
* navigation.
|
|
140
|
+
*/
|
|
141
|
+
beforeNav?: () => Promise<unknown>;
|
|
142
|
+
};
|
|
135
143
|
|
|
136
|
-
export type ClickableState = {
|
|
144
|
+
export type ClickableState = {
|
|
137
145
|
/**
|
|
138
146
|
* Whether the component is hovered.
|
|
139
147
|
*
|
|
140
148
|
* See component documentation for more details.
|
|
141
149
|
*/
|
|
142
|
-
hovered: boolean
|
|
143
|
-
|
|
150
|
+
hovered: boolean;
|
|
144
151
|
/**
|
|
145
152
|
* Whether the component is hovered.
|
|
146
153
|
*
|
|
147
154
|
* See component documentation for more details.
|
|
148
155
|
*/
|
|
149
|
-
focused: boolean
|
|
150
|
-
|
|
156
|
+
focused: boolean;
|
|
151
157
|
/**
|
|
152
158
|
* Whether the component is hovered.
|
|
153
159
|
*
|
|
154
160
|
* See component documentation for more details.
|
|
155
161
|
*/
|
|
156
|
-
pressed: boolean
|
|
157
|
-
|
|
162
|
+
pressed: boolean;
|
|
158
163
|
/**
|
|
159
164
|
* When we're waiting for beforeNav or safeWithNav to complete an async
|
|
160
165
|
* action, this will be true.
|
|
@@ -162,59 +167,29 @@ export type ClickableState = {|
|
|
|
162
167
|
* NOTE: We only wait for safeWithNav to complete when doing a full page
|
|
163
168
|
* load navigation.
|
|
164
169
|
*/
|
|
165
|
-
waiting: boolean
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
type
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
*
|
|
189
|
-
* WARNING: Using this with `target="_blank"` will trigger built-in popup
|
|
190
|
-
* blockers in Firefox and Safari. This is because we do navigation
|
|
191
|
-
* programmatically and `beforeNav` causes a delay which means that the
|
|
192
|
-
* browser can't make a directly link between a user action and the
|
|
193
|
-
* navigation.
|
|
194
|
-
*/
|
|
195
|
-
beforeNav?: () => Promise<mixed>,
|
|
196
|
-
|};
|
|
197
|
-
|
|
198
|
-
type DefaultProps = {|
|
|
199
|
-
disabled: $PropertyType<Props, "disabled">,
|
|
200
|
-
|};
|
|
201
|
-
|
|
202
|
-
export type ChildrenProps = {|
|
|
203
|
-
onClick: (e: SyntheticMouseEvent<>) => mixed,
|
|
204
|
-
onMouseEnter: (e: SyntheticMouseEvent<>) => mixed,
|
|
205
|
-
onMouseLeave: () => mixed,
|
|
206
|
-
onMouseDown: () => mixed,
|
|
207
|
-
onMouseUp: (e: SyntheticMouseEvent<>) => mixed,
|
|
208
|
-
onTouchStart: () => mixed,
|
|
209
|
-
onTouchEnd: () => mixed,
|
|
210
|
-
onTouchCancel: () => mixed,
|
|
211
|
-
onKeyDown: (e: SyntheticKeyboardEvent<>) => mixed,
|
|
212
|
-
onKeyUp: (e: SyntheticKeyboardEvent<>) => mixed,
|
|
213
|
-
onFocus: (e: SyntheticFocusEvent<>) => mixed,
|
|
214
|
-
onBlur: (e: SyntheticFocusEvent<>) => mixed,
|
|
215
|
-
tabIndex?: number,
|
|
216
|
-
rel?: string,
|
|
217
|
-
|};
|
|
170
|
+
waiting: boolean;
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
type DefaultProps = {
|
|
174
|
+
disabled: Props["disabled"];
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
export type ChildrenProps = {
|
|
178
|
+
onClick: (e: React.SyntheticEvent) => unknown;
|
|
179
|
+
onMouseEnter: (e: React.MouseEvent) => unknown;
|
|
180
|
+
onMouseLeave: () => unknown;
|
|
181
|
+
onMouseDown: () => unknown;
|
|
182
|
+
onMouseUp: (e: React.MouseEvent) => unknown;
|
|
183
|
+
onTouchStart: () => unknown;
|
|
184
|
+
onTouchEnd: () => unknown;
|
|
185
|
+
onTouchCancel: () => unknown;
|
|
186
|
+
onKeyDown: (e: React.KeyboardEvent) => unknown;
|
|
187
|
+
onKeyUp: (e: React.KeyboardEvent) => unknown;
|
|
188
|
+
onFocus: (e: React.FocusEvent) => unknown;
|
|
189
|
+
onBlur: (e: React.FocusEvent) => unknown;
|
|
190
|
+
tabIndex?: number;
|
|
191
|
+
rel?: string;
|
|
192
|
+
};
|
|
218
193
|
|
|
219
194
|
const disabledHandlers = {
|
|
220
195
|
onClick: () => void 0,
|
|
@@ -227,12 +202,12 @@ const disabledHandlers = {
|
|
|
227
202
|
onTouchCancel: () => void 0,
|
|
228
203
|
onKeyDown: () => void 0,
|
|
229
204
|
onKeyUp: () => void 0,
|
|
230
|
-
};
|
|
205
|
+
} as const;
|
|
231
206
|
|
|
232
207
|
const keyCodes = {
|
|
233
208
|
enter: 13,
|
|
234
209
|
space: 32,
|
|
235
|
-
};
|
|
210
|
+
} as const;
|
|
236
211
|
|
|
237
212
|
const startState: ClickableState = {
|
|
238
213
|
hovered: false,
|
|
@@ -324,7 +299,7 @@ const startState: ClickableState = {
|
|
|
324
299
|
*/
|
|
325
300
|
export default class ClickableBehavior extends React.Component<
|
|
326
301
|
Props,
|
|
327
|
-
ClickableState
|
|
302
|
+
ClickableState
|
|
328
303
|
> {
|
|
329
304
|
waitingForClick: boolean;
|
|
330
305
|
enterClick: boolean;
|
|
@@ -336,7 +311,7 @@ export default class ClickableBehavior extends React.Component<
|
|
|
336
311
|
static getDerivedStateFromProps(
|
|
337
312
|
props: Props,
|
|
338
313
|
state: ClickableState,
|
|
339
|
-
):
|
|
314
|
+
): Partial<ClickableState> | null | undefined {
|
|
340
315
|
// If new props are disabled, reset the hovered/pressed states
|
|
341
316
|
if (props.disabled) {
|
|
342
317
|
// Keep the focused state for enabling keyboard navigation.
|
|
@@ -382,7 +357,7 @@ export default class ClickableBehavior extends React.Component<
|
|
|
382
357
|
}
|
|
383
358
|
|
|
384
359
|
handleSafeWithNav(
|
|
385
|
-
safeWithNav: () => Promise<
|
|
360
|
+
safeWithNav: () => Promise<unknown>,
|
|
386
361
|
shouldNavigate: boolean,
|
|
387
362
|
): Promise<void> {
|
|
388
363
|
const {skipClientNav, history} = this.props;
|
|
@@ -423,7 +398,9 @@ export default class ClickableBehavior extends React.Component<
|
|
|
423
398
|
}
|
|
424
399
|
}
|
|
425
400
|
|
|
426
|
-
runCallbackAndMaybeNavigate(
|
|
401
|
+
runCallbackAndMaybeNavigate(
|
|
402
|
+
e: React.SyntheticEvent,
|
|
403
|
+
): Promise<undefined> | null | undefined {
|
|
427
404
|
const {
|
|
428
405
|
onClick = undefined,
|
|
429
406
|
beforeNav = undefined,
|
|
@@ -464,7 +441,7 @@ export default class ClickableBehavior extends React.Component<
|
|
|
464
441
|
// All events should be typed as SyntheticEvent<HTMLElement>.
|
|
465
442
|
// Updating all of the places will take some time so I'll do
|
|
466
443
|
// this later
|
|
467
|
-
//
|
|
444
|
+
// @ts-expect-error [FEI-5019] - TS2322 - Type 'HTMLElement | null' is not assignable to type 'EventTarget & Element'.
|
|
468
445
|
target = target.parentElement;
|
|
469
446
|
}
|
|
470
447
|
}
|
|
@@ -484,13 +461,14 @@ export default class ClickableBehavior extends React.Component<
|
|
|
484
461
|
})
|
|
485
462
|
.catch(() => {});
|
|
486
463
|
} else if (safeWithNav) {
|
|
464
|
+
// @ts-expect-error [FEI-5019] - TS2322 - Type 'Promise<void>' is not assignable to type 'Promise<undefined>'.
|
|
487
465
|
return this.handleSafeWithNav(safeWithNav, shouldNavigate);
|
|
488
466
|
} else {
|
|
489
467
|
this.navigateOrReset(shouldNavigate);
|
|
490
468
|
}
|
|
491
469
|
}
|
|
492
470
|
|
|
493
|
-
handleClick: (e:
|
|
471
|
+
handleClick: (e: React.SyntheticEvent) => void = (e) => {
|
|
494
472
|
const {
|
|
495
473
|
onClick = undefined,
|
|
496
474
|
beforeNav = undefined,
|
|
@@ -508,7 +486,7 @@ export default class ClickableBehavior extends React.Component<
|
|
|
508
486
|
this.runCallbackAndMaybeNavigate(e);
|
|
509
487
|
};
|
|
510
488
|
|
|
511
|
-
handleMouseEnter: (e:
|
|
489
|
+
handleMouseEnter: (e: React.MouseEvent) => void = (e) => {
|
|
512
490
|
if (!this.waitingForClick) {
|
|
513
491
|
this.setState({hovered: true});
|
|
514
492
|
}
|
|
@@ -524,7 +502,7 @@ export default class ClickableBehavior extends React.Component<
|
|
|
524
502
|
this.setState({pressed: true});
|
|
525
503
|
};
|
|
526
504
|
|
|
527
|
-
handleMouseUp: (e:
|
|
505
|
+
handleMouseUp: (e: React.MouseEvent) => void = (e) => {
|
|
528
506
|
this.setState({pressed: false, focused: false});
|
|
529
507
|
};
|
|
530
508
|
|
|
@@ -542,7 +520,7 @@ export default class ClickableBehavior extends React.Component<
|
|
|
542
520
|
this.waitingForClick = true;
|
|
543
521
|
};
|
|
544
522
|
|
|
545
|
-
handleKeyDown: (e:
|
|
523
|
+
handleKeyDown: (e: React.KeyboardEvent) => void = (e) => {
|
|
546
524
|
const {onKeyDown, role} = this.props;
|
|
547
525
|
if (onKeyDown) {
|
|
548
526
|
onKeyDown(e);
|
|
@@ -568,7 +546,7 @@ export default class ClickableBehavior extends React.Component<
|
|
|
568
546
|
}
|
|
569
547
|
};
|
|
570
548
|
|
|
571
|
-
handleKeyUp: (e:
|
|
549
|
+
handleKeyUp: (e: React.KeyboardEvent) => void = (e) => {
|
|
572
550
|
const {onKeyUp, role} = this.props;
|
|
573
551
|
if (onKeyUp) {
|
|
574
552
|
onKeyUp(e);
|
|
@@ -589,15 +567,15 @@ export default class ClickableBehavior extends React.Component<
|
|
|
589
567
|
}
|
|
590
568
|
};
|
|
591
569
|
|
|
592
|
-
handleFocus: (e:
|
|
570
|
+
handleFocus: (e: React.FocusEvent) => void = (e) => {
|
|
593
571
|
this.setState({focused: true});
|
|
594
572
|
};
|
|
595
573
|
|
|
596
|
-
handleBlur: (e:
|
|
574
|
+
handleBlur: (e: React.FocusEvent) => void = (e) => {
|
|
597
575
|
this.setState({focused: false, pressed: false});
|
|
598
576
|
};
|
|
599
577
|
|
|
600
|
-
render(): React.
|
|
578
|
+
render(): React.ReactElement {
|
|
601
579
|
const childrenProps: ChildrenProps = this.props.disabled
|
|
602
580
|
? {
|
|
603
581
|
...disabledHandlers,
|