@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
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# @khanacademy/wonder-blocks-clickable
|
|
2
2
|
|
|
3
|
+
## 2.4.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- d816af08: Update build and test configs use TypeScript
|
|
8
|
+
- 3891f544: Update babel config to include plugins that Storybook needed
|
|
9
|
+
- 0d28bb1c: Configured TypeScript
|
|
10
|
+
- 3d05f764: Fix HOCs and other type errors
|
|
11
|
+
- c2ec4902: Update eslint configuration, fix lint
|
|
12
|
+
- 2983c05b: Include 'types' field in package.json
|
|
13
|
+
- 77ff6a66: Generate Flow types from TypeScript types
|
|
14
|
+
- ec8d4b7f: Fix miscellaneous TypeScript errors
|
|
15
|
+
- Updated dependencies [d816af08]
|
|
16
|
+
- Updated dependencies [3891f544]
|
|
17
|
+
- Updated dependencies [0d28bb1c]
|
|
18
|
+
- Updated dependencies [873f4a14]
|
|
19
|
+
- Updated dependencies [3d05f764]
|
|
20
|
+
- Updated dependencies [c2ec4902]
|
|
21
|
+
- Updated dependencies [2983c05b]
|
|
22
|
+
- Updated dependencies [77ff6a66]
|
|
23
|
+
- Updated dependencies [ec8d4b7f]
|
|
24
|
+
- @khanacademy/wonder-blocks-color@1.2.2
|
|
25
|
+
- @khanacademy/wonder-blocks-core@4.8.0
|
|
26
|
+
|
|
27
|
+
## 2.4.5
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- 91cb727c: Remove file extensions from imports
|
|
32
|
+
- 91cb727c: Merge disjoint prop types since the codemod doesn't handle these properly.
|
|
33
|
+
- Updated dependencies [91cb727c]
|
|
34
|
+
- Updated dependencies [91cb727c]
|
|
35
|
+
- @khanacademy/wonder-blocks-color@1.2.1
|
|
36
|
+
- @khanacademy/wonder-blocks-core@4.7.0
|
|
37
|
+
|
|
3
38
|
## 2.4.4
|
|
4
39
|
|
|
5
40
|
### Patch Changes
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export type ClickableRole = "button" | "link" | "checkbox" | "radio" | "listbox" | "option" | "menuitem" | "menu" | "tab";
|
|
3
|
+
type Props = {
|
|
4
|
+
/**
|
|
5
|
+
* A function that returns the a React `Element`.
|
|
6
|
+
*
|
|
7
|
+
* The React `Element` returned should take in this component's state
|
|
8
|
+
* (`{hovered, focused, pressed}`) as props.
|
|
9
|
+
*/
|
|
10
|
+
children: (state: ClickableState, childrenProps: ChildrenProps) => React.ReactElement;
|
|
11
|
+
/**
|
|
12
|
+
* Whether the component is disabled.
|
|
13
|
+
*
|
|
14
|
+
* If the component is disabled, this component will return handlers
|
|
15
|
+
* that do nothing.
|
|
16
|
+
*/
|
|
17
|
+
disabled: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* A URL.
|
|
20
|
+
*
|
|
21
|
+
* If specified, clicking on the component will navigate to the location
|
|
22
|
+
* provided.
|
|
23
|
+
* For keyboard navigation, the default is that both an enter and space
|
|
24
|
+
* press would also navigate to this location. See the triggerOnEnter and
|
|
25
|
+
* triggerOnSpace props for more details.
|
|
26
|
+
*/
|
|
27
|
+
href?: string;
|
|
28
|
+
/**
|
|
29
|
+
* This should only be used by button.js.
|
|
30
|
+
*/
|
|
31
|
+
type?: "submit";
|
|
32
|
+
/**
|
|
33
|
+
* Specifies the type of relationship between the current document and the
|
|
34
|
+
* linked document. Should only be used when `href` is specified. This
|
|
35
|
+
* defaults to "noopener noreferrer" when `target="_blank"`, but can be
|
|
36
|
+
* overridden by setting this prop to something else.
|
|
37
|
+
*/
|
|
38
|
+
rel?: string;
|
|
39
|
+
skipClientNav?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Used to indicate the tab order of an element.
|
|
42
|
+
* Use 0 to make an element focusable, and use -1 to make an
|
|
43
|
+
* element non-focusable via keyboard navigation.
|
|
44
|
+
*/
|
|
45
|
+
tabIndex?: number;
|
|
46
|
+
/**
|
|
47
|
+
* A function to be executed `onclick`.
|
|
48
|
+
*/
|
|
49
|
+
onClick?: (e: React.SyntheticEvent) => unknown;
|
|
50
|
+
/**
|
|
51
|
+
* Run async code in the background while client-side navigating. If the
|
|
52
|
+
* browser does a full page load navigation, the callback promise must be
|
|
53
|
+
* settled before the navigation will occur. Errors are ignored so that
|
|
54
|
+
* navigation is guaranteed to succeed.
|
|
55
|
+
*/
|
|
56
|
+
safeWithNav?: () => Promise<unknown>;
|
|
57
|
+
/**
|
|
58
|
+
* Passed in by withRouter HOC.
|
|
59
|
+
* @ignore
|
|
60
|
+
*/
|
|
61
|
+
history?: any;
|
|
62
|
+
/**
|
|
63
|
+
* A role that encapsulates how the clickable component should behave, which
|
|
64
|
+
* affects which keyboard actions trigger the component. For example, a
|
|
65
|
+
* component with role="button" should be able to be clicked with both the
|
|
66
|
+
* enter and space keys.
|
|
67
|
+
*/
|
|
68
|
+
role?: ClickableRole;
|
|
69
|
+
/**
|
|
70
|
+
* Respond to raw "keydown" event.
|
|
71
|
+
*/
|
|
72
|
+
onKeyDown?: (e: React.KeyboardEvent) => unknown;
|
|
73
|
+
/**
|
|
74
|
+
* Respond to raw "keyup" event.
|
|
75
|
+
*/
|
|
76
|
+
onKeyUp?: (e: React.KeyboardEvent) => unknown;
|
|
77
|
+
/**
|
|
78
|
+
* A target destination window for a link to open in. Should only be used
|
|
79
|
+
* when `href` is specified.
|
|
80
|
+
*/
|
|
81
|
+
target?: "_blank";
|
|
82
|
+
/**
|
|
83
|
+
* Run async code before navigating to the URL passed to `href`. If the
|
|
84
|
+
* promise returned rejects then navigation will not occur.
|
|
85
|
+
*
|
|
86
|
+
* If both safeWithNav and beforeNav are provided, beforeNav will be run
|
|
87
|
+
* first and safeWithNav will only be run if beforeNav does not reject.
|
|
88
|
+
*
|
|
89
|
+
* WARNING: Using this with `target="_blank"` will trigger built-in popup
|
|
90
|
+
* blockers in Firefox and Safari. This is because we do navigation
|
|
91
|
+
* programmatically and `beforeNav` causes a delay which means that the
|
|
92
|
+
* browser can't make a directly link between a user action and the
|
|
93
|
+
* navigation.
|
|
94
|
+
*/
|
|
95
|
+
beforeNav?: () => Promise<unknown>;
|
|
96
|
+
};
|
|
97
|
+
export type ClickableState = {
|
|
98
|
+
/**
|
|
99
|
+
* Whether the component is hovered.
|
|
100
|
+
*
|
|
101
|
+
* See component documentation for more details.
|
|
102
|
+
*/
|
|
103
|
+
hovered: boolean;
|
|
104
|
+
/**
|
|
105
|
+
* Whether the component is hovered.
|
|
106
|
+
*
|
|
107
|
+
* See component documentation for more details.
|
|
108
|
+
*/
|
|
109
|
+
focused: boolean;
|
|
110
|
+
/**
|
|
111
|
+
* Whether the component is hovered.
|
|
112
|
+
*
|
|
113
|
+
* See component documentation for more details.
|
|
114
|
+
*/
|
|
115
|
+
pressed: boolean;
|
|
116
|
+
/**
|
|
117
|
+
* When we're waiting for beforeNav or safeWithNav to complete an async
|
|
118
|
+
* action, this will be true.
|
|
119
|
+
*
|
|
120
|
+
* NOTE: We only wait for safeWithNav to complete when doing a full page
|
|
121
|
+
* load navigation.
|
|
122
|
+
*/
|
|
123
|
+
waiting: boolean;
|
|
124
|
+
};
|
|
125
|
+
type DefaultProps = {
|
|
126
|
+
disabled: Props["disabled"];
|
|
127
|
+
};
|
|
128
|
+
export type ChildrenProps = {
|
|
129
|
+
onClick: (e: React.SyntheticEvent) => unknown;
|
|
130
|
+
onMouseEnter: (e: React.MouseEvent) => unknown;
|
|
131
|
+
onMouseLeave: () => unknown;
|
|
132
|
+
onMouseDown: () => unknown;
|
|
133
|
+
onMouseUp: (e: React.MouseEvent) => unknown;
|
|
134
|
+
onTouchStart: () => unknown;
|
|
135
|
+
onTouchEnd: () => unknown;
|
|
136
|
+
onTouchCancel: () => unknown;
|
|
137
|
+
onKeyDown: (e: React.KeyboardEvent) => unknown;
|
|
138
|
+
onKeyUp: (e: React.KeyboardEvent) => unknown;
|
|
139
|
+
onFocus: (e: React.FocusEvent) => unknown;
|
|
140
|
+
onBlur: (e: React.FocusEvent) => unknown;
|
|
141
|
+
tabIndex?: number;
|
|
142
|
+
rel?: string;
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Add hover, focus, and active status updates to a clickable component.
|
|
146
|
+
*
|
|
147
|
+
* Via mouse:
|
|
148
|
+
*
|
|
149
|
+
* 1. Hover over button -> hover state
|
|
150
|
+
* 2. Mouse down -> active state
|
|
151
|
+
* 3. Mouse up -> default state
|
|
152
|
+
* 4. Press tab -> focus state
|
|
153
|
+
*
|
|
154
|
+
* Via touch:
|
|
155
|
+
*
|
|
156
|
+
* 1. Touch down -> press state
|
|
157
|
+
* 2. Touch up -> default state
|
|
158
|
+
*
|
|
159
|
+
* Via keyboard:
|
|
160
|
+
*
|
|
161
|
+
* 1. Tab to focus -> focus state
|
|
162
|
+
* 2. Keydown (spacebar/enter) -> active state
|
|
163
|
+
* 3. Keyup (spacebar/enter) -> focus state
|
|
164
|
+
*
|
|
165
|
+
* Warning: The event handlers returned (onClick, onMouseEnter, onMouseLeave,
|
|
166
|
+
* onMouseDown, onMouseUp, onTouchStart, onTouchEnd, onTouchCancel,
|
|
167
|
+
* onKeyDown, onKeyUp, onFocus, onBlur, tabIndex) should be passed on to the
|
|
168
|
+
* component that has the ClickableBehavior. You cannot override these handlers
|
|
169
|
+
* without potentially breaking the functionality of ClickableBehavior.
|
|
170
|
+
*
|
|
171
|
+
* There are internal props triggerOnEnter and triggerOnSpace that can be set to
|
|
172
|
+
* false if one of those keys shouldn't count as a click on this component. Be
|
|
173
|
+
* careful about setting those to false -- make certain that the component
|
|
174
|
+
* shouldn't process that key.
|
|
175
|
+
*
|
|
176
|
+
* See [this
|
|
177
|
+
document](https://docs.google.com/document/d/1DG5Rg2f0cawIL5R8UqnPQpd7pbdObk8OyjO5ryYQmBM/edit#)
|
|
178
|
+
for a more thorough explanation of expected behaviors and potential cavaets.
|
|
179
|
+
*
|
|
180
|
+
* `ClickableBehavior` accepts a function as `children` which is passed state
|
|
181
|
+
* and an object containing event handlers and some other props. The `children`
|
|
182
|
+
* function should return a clickable React Element of some sort.
|
|
183
|
+
*
|
|
184
|
+
* Example:
|
|
185
|
+
*
|
|
186
|
+
* ```jsx
|
|
187
|
+
* function MyClickableComponent(props: Props) {
|
|
188
|
+
* const ClickableBehavior = getClickableBehavior();
|
|
189
|
+
*
|
|
190
|
+
* return (
|
|
191
|
+
* <ClickableBehavior
|
|
192
|
+
* disabled={props.disabled}
|
|
193
|
+
* onClick={props.onClick}
|
|
194
|
+
* tabIndex={0}
|
|
195
|
+
* >
|
|
196
|
+
* {({hovered}, childrenProps) => (
|
|
197
|
+
* <RoundRect
|
|
198
|
+
* textcolor="white"
|
|
199
|
+
* backgroundColor={hovered ? "red" : "blue"}
|
|
200
|
+
* {...childrenProps}
|
|
201
|
+
* >
|
|
202
|
+
* {props.children}
|
|
203
|
+
* </RoundRect>
|
|
204
|
+
* )}
|
|
205
|
+
* </ClickableBehavior>
|
|
206
|
+
* );
|
|
207
|
+
* }
|
|
208
|
+
* ```
|
|
209
|
+
*
|
|
210
|
+
* This follows a pattern called [Function as Child
|
|
211
|
+
* Components](https://medium.com/merrickchristensen/function-as-child-components-5f3920a9ace9).
|
|
212
|
+
*
|
|
213
|
+
* **WARNING:** Do not use this component directly, use getClickableBehavior
|
|
214
|
+
* instead. getClickableBehavior takes three arguments (href, directtNav, and
|
|
215
|
+
* router) and returns either the default ClickableBehavior or a react-router
|
|
216
|
+
* aware version.
|
|
217
|
+
*
|
|
218
|
+
* The react-router aware version is returned if `router` is a react-router-dom
|
|
219
|
+
* router, `skipClientNav` is not `true`, and `href` is an internal URL.
|
|
220
|
+
*
|
|
221
|
+
* The `router` can be accessed via __RouterContext (imported from
|
|
222
|
+
'react-router') from a component rendered as a descendant of a BrowserRouter.
|
|
223
|
+
See https://reacttraining.com/react-router/web/guides/basic-components.
|
|
224
|
+
*/
|
|
225
|
+
export default class ClickableBehavior extends React.Component<Props, ClickableState> {
|
|
226
|
+
waitingForClick: boolean;
|
|
227
|
+
enterClick: boolean;
|
|
228
|
+
static defaultProps: DefaultProps;
|
|
229
|
+
static getDerivedStateFromProps(props: Props, state: ClickableState): Partial<ClickableState> | null | undefined;
|
|
230
|
+
constructor(props: Props);
|
|
231
|
+
navigateOrReset(shouldNavigate: boolean): void;
|
|
232
|
+
handleSafeWithNav(safeWithNav: () => Promise<unknown>, shouldNavigate: boolean): Promise<void>;
|
|
233
|
+
runCallbackAndMaybeNavigate(e: React.SyntheticEvent): Promise<undefined> | null | undefined;
|
|
234
|
+
handleClick: (e: React.SyntheticEvent) => void;
|
|
235
|
+
handleMouseEnter: (e: React.MouseEvent) => void;
|
|
236
|
+
handleMouseLeave: () => void;
|
|
237
|
+
handleMouseDown: () => void;
|
|
238
|
+
handleMouseUp: (e: React.MouseEvent) => void;
|
|
239
|
+
handleTouchStart: () => void;
|
|
240
|
+
handleTouchEnd: () => void;
|
|
241
|
+
handleTouchCancel: () => void;
|
|
242
|
+
handleKeyDown: (e: React.KeyboardEvent) => void;
|
|
243
|
+
handleKeyUp: (e: React.KeyboardEvent) => void;
|
|
244
|
+
handleFocus: (e: React.FocusEvent) => void;
|
|
245
|
+
handleBlur: (e: React.FocusEvent) => void;
|
|
246
|
+
render(): React.ReactElement;
|
|
247
|
+
}
|
|
248
|
+
export {};
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flowtype definitions for clickable-behavior
|
|
3
|
+
* Generated by Flowgen from a Typescript Definition
|
|
4
|
+
* Flowgen v1.21.0
|
|
5
|
+
* @flow
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import * as React from "react";
|
|
9
|
+
export type ClickableRole =
|
|
10
|
+
| "button"
|
|
11
|
+
| "link"
|
|
12
|
+
| "checkbox"
|
|
13
|
+
| "radio"
|
|
14
|
+
| "listbox"
|
|
15
|
+
| "option"
|
|
16
|
+
| "menuitem"
|
|
17
|
+
| "menu"
|
|
18
|
+
| "tab";
|
|
19
|
+
declare type Props = {
|
|
20
|
+
/**
|
|
21
|
+
* A function that returns the a React `Element`.
|
|
22
|
+
*
|
|
23
|
+
* The React `Element` returned should take in this component's state
|
|
24
|
+
* (`{hovered, focused, pressed}`) as props.
|
|
25
|
+
*/
|
|
26
|
+
children: (
|
|
27
|
+
state: ClickableState,
|
|
28
|
+
childrenProps: ChildrenProps
|
|
29
|
+
) => React.Element<>,
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Whether the component is disabled.
|
|
33
|
+
*
|
|
34
|
+
* If the component is disabled, this component will return handlers
|
|
35
|
+
* that do nothing.
|
|
36
|
+
*/
|
|
37
|
+
disabled: boolean,
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* A URL.
|
|
41
|
+
*
|
|
42
|
+
* If specified, clicking on the component will navigate to the location
|
|
43
|
+
* provided.
|
|
44
|
+
* For keyboard navigation, the default is that both an enter and space
|
|
45
|
+
* press would also navigate to this location. See the triggerOnEnter and
|
|
46
|
+
* triggerOnSpace props for more details.
|
|
47
|
+
*/
|
|
48
|
+
href?: string,
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* This should only be used by button.js.
|
|
52
|
+
*/
|
|
53
|
+
type?: "submit",
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Specifies the type of relationship between the current document and the
|
|
57
|
+
* linked document. Should only be used when `href` is specified. This
|
|
58
|
+
* defaults to "noopener noreferrer" when `target="_blank"`, but can be
|
|
59
|
+
* overridden by setting this prop to something else.
|
|
60
|
+
*/
|
|
61
|
+
rel?: string,
|
|
62
|
+
skipClientNav?: boolean,
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Used to indicate the tab order of an element.
|
|
66
|
+
* Use 0 to make an element focusable, and use -1 to make an
|
|
67
|
+
* element non-focusable via keyboard navigation.
|
|
68
|
+
*/
|
|
69
|
+
tabIndex?: number,
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* A function to be executed `onclick`.
|
|
73
|
+
*/
|
|
74
|
+
onClick?: (e: React.SyntheticEvent<>) => mixed,
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Run async code in the background while client-side navigating. If the
|
|
78
|
+
* browser does a full page load navigation, the callback promise must be
|
|
79
|
+
* settled before the navigation will occur. Errors are ignored so that
|
|
80
|
+
* navigation is guaranteed to succeed.
|
|
81
|
+
*/
|
|
82
|
+
safeWithNav?: () => Promise<mixed>,
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Passed in by withRouter HOC.
|
|
86
|
+
* @ignore
|
|
87
|
+
*/
|
|
88
|
+
history?: any,
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* A role that encapsulates how the clickable component should behave, which
|
|
92
|
+
* affects which keyboard actions trigger the component. For example, a
|
|
93
|
+
* component with role="button" should be able to be clicked with both the
|
|
94
|
+
* enter and space keys.
|
|
95
|
+
*/
|
|
96
|
+
role?: ClickableRole,
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Respond to raw "keydown" event.
|
|
100
|
+
*/
|
|
101
|
+
onKeyDown?: (e: React.KeyboardEvent<>) => mixed,
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Respond to raw "keyup" event.
|
|
105
|
+
*/
|
|
106
|
+
onKeyUp?: (e: React.KeyboardEvent<>) => mixed,
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* A target destination window for a link to open in. Should only be used
|
|
110
|
+
* when `href` is specified.
|
|
111
|
+
*/
|
|
112
|
+
target?: "_blank",
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Run async code before navigating to the URL passed to `href`. If the
|
|
116
|
+
* promise returned rejects then navigation will not occur.
|
|
117
|
+
*
|
|
118
|
+
* If both safeWithNav and beforeNav are provided, beforeNav will be run
|
|
119
|
+
* first and safeWithNav will only be run if beforeNav does not reject.
|
|
120
|
+
*
|
|
121
|
+
* WARNING: Using this with `target="_blank"` will trigger built-in popup
|
|
122
|
+
* blockers in Firefox and Safari. This is because we do navigation
|
|
123
|
+
* programmatically and `beforeNav` causes a delay which means that the
|
|
124
|
+
* browser can't make a directly link between a user action and the
|
|
125
|
+
* navigation.
|
|
126
|
+
*/
|
|
127
|
+
beforeNav?: () => Promise<mixed>,
|
|
128
|
+
...
|
|
129
|
+
};
|
|
130
|
+
export type ClickableState = {
|
|
131
|
+
/**
|
|
132
|
+
* Whether the component is hovered.
|
|
133
|
+
*
|
|
134
|
+
* See component documentation for more details.
|
|
135
|
+
*/
|
|
136
|
+
hovered: boolean,
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Whether the component is hovered.
|
|
140
|
+
*
|
|
141
|
+
* See component documentation for more details.
|
|
142
|
+
*/
|
|
143
|
+
focused: boolean,
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Whether the component is hovered.
|
|
147
|
+
*
|
|
148
|
+
* See component documentation for more details.
|
|
149
|
+
*/
|
|
150
|
+
pressed: boolean,
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* When we're waiting for beforeNav or safeWithNav to complete an async
|
|
154
|
+
* action, this will be true.
|
|
155
|
+
*
|
|
156
|
+
* NOTE: We only wait for safeWithNav to complete when doing a full page
|
|
157
|
+
* load navigation.
|
|
158
|
+
*/
|
|
159
|
+
waiting: boolean,
|
|
160
|
+
...
|
|
161
|
+
};
|
|
162
|
+
declare type DefaultProps = {
|
|
163
|
+
disabled: $PropertyType<Props, "disabled">,
|
|
164
|
+
...
|
|
165
|
+
};
|
|
166
|
+
export type ChildrenProps = {
|
|
167
|
+
onClick: (e: React.SyntheticEvent<>) => mixed,
|
|
168
|
+
onMouseEnter: (e: React.MouseEvent<>) => mixed,
|
|
169
|
+
onMouseLeave: () => mixed,
|
|
170
|
+
onMouseDown: () => mixed,
|
|
171
|
+
onMouseUp: (e: React.MouseEvent<>) => mixed,
|
|
172
|
+
onTouchStart: () => mixed,
|
|
173
|
+
onTouchEnd: () => mixed,
|
|
174
|
+
onTouchCancel: () => mixed,
|
|
175
|
+
onKeyDown: (e: React.KeyboardEvent<>) => mixed,
|
|
176
|
+
onKeyUp: (e: React.KeyboardEvent<>) => mixed,
|
|
177
|
+
onFocus: (e: React.FocusEvent<>) => mixed,
|
|
178
|
+
onBlur: (e: React.FocusEvent<>) => mixed,
|
|
179
|
+
tabIndex?: number,
|
|
180
|
+
rel?: string,
|
|
181
|
+
...
|
|
182
|
+
};
|
|
183
|
+
/**
|
|
184
|
+
* Add hover, focus, and active status updates to a clickable component.
|
|
185
|
+
*
|
|
186
|
+
* Via mouse:
|
|
187
|
+
*
|
|
188
|
+
* 1. Hover over button -> hover state
|
|
189
|
+
* 2. Mouse down -> active state
|
|
190
|
+
* 3. Mouse up -> default state
|
|
191
|
+
* 4. Press tab -> focus state
|
|
192
|
+
*
|
|
193
|
+
* Via touch:
|
|
194
|
+
*
|
|
195
|
+
* 1. Touch down -> press state
|
|
196
|
+
* 2. Touch up -> default state
|
|
197
|
+
*
|
|
198
|
+
* Via keyboard:
|
|
199
|
+
*
|
|
200
|
+
* 1. Tab to focus -> focus state
|
|
201
|
+
* 2. Keydown (spacebar/enter) -> active state
|
|
202
|
+
* 3. Keyup (spacebar/enter) -> focus state
|
|
203
|
+
*
|
|
204
|
+
* Warning: The event handlers returned (onClick, onMouseEnter, onMouseLeave,
|
|
205
|
+
* onMouseDown, onMouseUp, onTouchStart, onTouchEnd, onTouchCancel,
|
|
206
|
+
* onKeyDown, onKeyUp, onFocus, onBlur, tabIndex) should be passed on to the
|
|
207
|
+
* component that has the ClickableBehavior. You cannot override these handlers
|
|
208
|
+
* without potentially breaking the functionality of ClickableBehavior.
|
|
209
|
+
*
|
|
210
|
+
* There are internal props triggerOnEnter and triggerOnSpace that can be set to
|
|
211
|
+
* false if one of those keys shouldn't count as a click on this component. Be
|
|
212
|
+
* careful about setting those to false -- make certain that the component
|
|
213
|
+
* shouldn't process that key.
|
|
214
|
+
*
|
|
215
|
+
* See [this
|
|
216
|
+
* document](https://docs.google.com/document/d/1DG5Rg2f0cawIL5R8UqnPQpd7pbdObk8OyjO5ryYQmBM/edit#)
|
|
217
|
+
* for a more thorough explanation of expected behaviors and potential cavaets.
|
|
218
|
+
*
|
|
219
|
+
* `ClickableBehavior` accepts a function as `children` which is passed state
|
|
220
|
+
* and an object containing event handlers and some other props. The `children`
|
|
221
|
+
* function should return a clickable React Element of some sort.
|
|
222
|
+
*
|
|
223
|
+
* Example:
|
|
224
|
+
*
|
|
225
|
+
* ```jsx
|
|
226
|
+
* function MyClickableComponent(props: Props) {
|
|
227
|
+
* const ClickableBehavior = getClickableBehavior();
|
|
228
|
+
*
|
|
229
|
+
* return (
|
|
230
|
+
* <ClickableBehavior
|
|
231
|
+
* disabled={props.disabled}
|
|
232
|
+
* onClick={props.onClick}
|
|
233
|
+
* tabIndex={0}
|
|
234
|
+
* >
|
|
235
|
+
* {({hovered}, childrenProps) => (
|
|
236
|
+
* <RoundRect
|
|
237
|
+
* textcolor="white"
|
|
238
|
+
* backgroundColor={hovered ? "red" : "blue"}
|
|
239
|
+
* {...childrenProps}
|
|
240
|
+
* >
|
|
241
|
+
* {props.children}
|
|
242
|
+
* </RoundRect>
|
|
243
|
+
* )}
|
|
244
|
+
* </ClickableBehavior>
|
|
245
|
+
* );
|
|
246
|
+
* }
|
|
247
|
+
* ```
|
|
248
|
+
*
|
|
249
|
+
* This follows a pattern called [Function as Child
|
|
250
|
+
* Components](https://medium.com/merrickchristensen/function-as-child-components-5f3920a9ace9).
|
|
251
|
+
*
|
|
252
|
+
* **WARNING:** Do not use this component directly, use getClickableBehavior
|
|
253
|
+
* instead. getClickableBehavior takes three arguments (href, directtNav, and
|
|
254
|
+
* router) and returns either the default ClickableBehavior or a react-router
|
|
255
|
+
* aware version.
|
|
256
|
+
*
|
|
257
|
+
* The react-router aware version is returned if `router` is a react-router-dom
|
|
258
|
+
* router, `skipClientNav` is not `true`, and `href` is an internal URL.
|
|
259
|
+
*
|
|
260
|
+
* The `router` can be accessed via __RouterContext (imported from
|
|
261
|
+
* 'react-router') from a component rendered as a descendant of a BrowserRouter.
|
|
262
|
+
* See https://reacttraining.com/react-router/web/guides/basic-components.
|
|
263
|
+
*/
|
|
264
|
+
declare export default class ClickableBehavior
|
|
265
|
+
mixins React.Component<Props, ClickableState>
|
|
266
|
+
{
|
|
267
|
+
waitingForClick: boolean;
|
|
268
|
+
enterClick: boolean;
|
|
269
|
+
static defaultProps: DefaultProps;
|
|
270
|
+
static getDerivedStateFromProps(
|
|
271
|
+
props: Props,
|
|
272
|
+
state: ClickableState
|
|
273
|
+
): $Rest<ClickableState, { ... }> | null | void;
|
|
274
|
+
constructor(props: Props): this;
|
|
275
|
+
navigateOrReset(shouldNavigate: boolean): void;
|
|
276
|
+
handleSafeWithNav(
|
|
277
|
+
safeWithNav: () => Promise<mixed>,
|
|
278
|
+
shouldNavigate: boolean
|
|
279
|
+
): Promise<void>;
|
|
280
|
+
runCallbackAndMaybeNavigate(
|
|
281
|
+
e: React.SyntheticEvent<>
|
|
282
|
+
): Promise<void> | null | void;
|
|
283
|
+
handleClick: (e: React.SyntheticEvent<>) => void;
|
|
284
|
+
handleMouseEnter: (e: React.MouseEvent<>) => void;
|
|
285
|
+
handleMouseLeave: () => void;
|
|
286
|
+
handleMouseDown: () => void;
|
|
287
|
+
handleMouseUp: (e: React.MouseEvent<>) => void;
|
|
288
|
+
handleTouchStart: () => void;
|
|
289
|
+
handleTouchEnd: () => void;
|
|
290
|
+
handleTouchCancel: () => void;
|
|
291
|
+
handleKeyDown: (e: React.KeyboardEvent<>) => void;
|
|
292
|
+
handleKeyUp: (e: React.KeyboardEvent<>) => void;
|
|
293
|
+
handleFocus: (e: React.FocusEvent<>) => void;
|
|
294
|
+
handleBlur: (e: React.FocusEvent<>) => void;
|
|
295
|
+
render(): React.Element<>;
|
|
296
|
+
}
|