@khanacademy/wonder-blocks-button 3.0.14 → 3.0.16

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.
@@ -1,347 +0,0 @@
1
- // @flow
2
- import * as React from "react";
3
- import {__RouterContext} from "react-router";
4
-
5
- import {getClickableBehavior} from "@khanacademy/wonder-blocks-clickable";
6
- import type {AriaProps, StyleType} from "@khanacademy/wonder-blocks-core";
7
- import type {IconAsset} from "@khanacademy/wonder-blocks-icon";
8
- import ButtonCore from "./button-core";
9
-
10
- export type SharedProps = {|
11
- /**
12
- * aria-label should be used when `spinner={true}` to let people using screen
13
- * readers that the action taken by clicking the button will take some
14
- * time to complete.
15
- */
16
- ...$Rest<AriaProps, {|"aria-disabled": "true" | "false" | void|}>,
17
-
18
- /**
19
- * Text to appear on the button.
20
- */
21
- children: string,
22
-
23
- /**
24
- * An icon, displayed to the left of the title.
25
- */
26
- icon?: IconAsset,
27
-
28
- /**
29
- * If true, replaces the contents with a spinner.
30
- *
31
- * Note: setting this prop to `true` will disable the button.
32
- *
33
- * TODO(kevinb): support spinner + light once we have designs
34
- */
35
- spinner: boolean,
36
-
37
- /**
38
- * The color of the button, either blue or red.
39
- */
40
- color: "default" | "destructive",
41
-
42
- /**
43
- * The kind of the button, either primary, secondary, or tertiary.
44
- *
45
- * In default state:
46
- *
47
- * - Primary buttons have background colors
48
- * - Secondary buttons have a border and no background color
49
- * - Tertiary buttons have no background or border
50
- */
51
- kind: "primary" | "secondary" | "tertiary",
52
-
53
- /**
54
- * Whether the button is on a dark/colored background.
55
- *
56
- * Sets primary button background color to white, and secondary and
57
- * tertiary button title to color.
58
- */
59
- light: boolean,
60
-
61
- /**
62
- * The size of the button. "medium" = height: 40; "small" = height: 32;
63
- * "large" = height: 56;
64
- */
65
- size: "medium" | "small" | "large",
66
-
67
- /**
68
- * Whether the button is disabled.
69
- */
70
- disabled: boolean,
71
-
72
- /**
73
- * An optional id attribute.
74
- */
75
- id?: string,
76
-
77
- /**
78
- * Test ID used for e2e testing.
79
- */
80
- testId?: string,
81
-
82
- /**
83
- * Specifies the type of relationship between the current document and the
84
- * linked document. Should only be used when `href` is specified. This
85
- * defaults to "noopener noreferrer" when `target="_blank"`, but can be
86
- * overridden by setting this prop to something else.
87
- */
88
- rel?: string,
89
-
90
- /**
91
- * A target destination window for a link to open in. Should only be used
92
- * when `href` is specified.
93
- *
94
- * TODO(WB-1262): only allow this prop when `href` is also set.t
95
- */
96
- target?: "_blank",
97
-
98
- /**
99
- * Set the tabindex attribute on the rendered element.
100
- */
101
- tabIndex?: number,
102
-
103
- /**
104
- * Whether to avoid using client-side navigation.
105
- *
106
- * If the URL passed to href is local to the client-side, e.g.
107
- * /math/algebra/eval-exprs, then it tries to use react-router-dom's Link
108
- * component which handles the client-side navigation. You can set
109
- * `skipClientNav` to true avoid using client-side nav entirely.
110
- *
111
- * NOTE: All URLs containing a protocol are considered external, e.g.
112
- * https://khanacademy.org/math/algebra/eval-exprs will trigger a full
113
- * page reload.
114
- */
115
- skipClientNav?: boolean,
116
-
117
- /**
118
- * Optional custom styles.
119
- */
120
- style?: StyleType,
121
- // TODO(yejia): use this if ADR #47 has been implemented
122
- /*
123
- style?: Style<Exact<{
124
- width?: number | string
125
- position: Position,
126
- ...MarginStyles,
127
- ...FlexItemStyles,
128
- }>>,
129
- */
130
-
131
- /**
132
- * Adds CSS classes to the Button.
133
- */
134
- className?: string,
135
-
136
- // NOTE(jeresig): Currently React Docgen (used by Styleguidist) doesn't
137
- // support ... inside of an exact object type. Thus we had to move the
138
- // following propers into this SharedProps, even though they should be
139
- // external. Once that's fixed we can split them back apart.
140
-
141
- /**
142
- * Function to call when button is clicked.
143
- *
144
- * This callback should be used for running synchronous code, like
145
- * dispatching a Redux action. For asynchronous code see the
146
- * beforeNav and safeWithNav props. It should NOT be used to redirect
147
- * to a different URL.
148
- *
149
- * Note: onClick is optional if href is present, but must be defined if
150
- * href is not
151
- */
152
- onClick?: (e: SyntheticEvent<>) => mixed,
153
- |};
154
-
155
- // We structure the props in this way to ensure that whenever we're using
156
- // beforeNav or safeWithNav that we're also using href. We also need to specify
157
- // a number of different variations to avoid ambigious situations where flow
158
- // finds more than one valid object type in the disjoint union.
159
- type Props =
160
- | {|
161
- ...SharedProps,
162
-
163
- /**
164
- * URL to navigate to.
165
- */
166
- href?: string,
167
- |}
168
- | {|
169
- ...SharedProps,
170
-
171
- /**
172
- * Used for buttons within <form>s.
173
- */
174
- type: "submit",
175
- |}
176
- | {|
177
- ...SharedProps,
178
-
179
- href: string,
180
-
181
- /**
182
- * Run async code before navigating. If the promise returned rejects then
183
- * navigation will not occur.
184
- *
185
- * If both safeWithNav and beforeNav are provided, beforeNav will be run
186
- * first and safeWithNav will only be run if beforeNav does not reject.
187
- */
188
- beforeNav: () => Promise<mixed>,
189
- |}
190
- | {|
191
- ...SharedProps,
192
-
193
- href: string,
194
-
195
- /**
196
- * Run async code in the background while client-side navigating. If the
197
- * browser does a full page load navigation, the callback promise must be
198
- * settled before the navigation will occur. Errors are ignored so that
199
- * navigation is guaranteed to succeed.
200
- */
201
- safeWithNav: () => Promise<mixed>,
202
- |}
203
- | {|
204
- ...SharedProps,
205
-
206
- href: string,
207
-
208
- /**
209
- * Run async code before navigating. If the promise returned rejects then
210
- * navigation will not occur.
211
- *
212
- * If both safeWithNav and beforeNav are provided, beforeNav will be run
213
- * first and safeWithNav will only be run if beforeNav does not reject.
214
- */
215
- beforeNav: () => Promise<mixed>,
216
-
217
- /**
218
- * Run async code in the background while client-side navigating. If the
219
- * browser does a full page load navigation, the callback promise must be
220
- * settled before the navigation will occur. Errors are ignored so that
221
- * navigation is guaranteed to succeed.
222
- */
223
- safeWithNav: () => Promise<mixed>,
224
- |};
225
-
226
- type DefaultProps = {|
227
- color: $PropertyType<Props, "color">,
228
- kind: $PropertyType<Props, "kind">,
229
- light: $PropertyType<Props, "light">,
230
- size: $PropertyType<Props, "size">,
231
- disabled: $PropertyType<Props, "disabled">,
232
- spinner: $PropertyType<Props, "spinner">,
233
- |};
234
-
235
- /**
236
- * Reusable button component.
237
- *
238
- * Consisting of a [`ClickableBehavior`](#clickablebehavior) surrounding a
239
- * `ButtonCore`. `ClickableBehavior` handles interactions and state changes.
240
- * `ButtonCore` is a stateless component which displays the different states
241
- * the `Button` can take.
242
- *
243
- * ### Usage
244
- *
245
- * ```jsx
246
- * import Button from "@khanacademy/wonder-blocks-button";
247
- *
248
- * <Button
249
- * onClick={(e) => console.log("Hello, world!")}
250
- * >
251
- * Hello, world!
252
- * </Button>
253
- * ```
254
- */
255
- export default class Button extends React.Component<Props> {
256
- static defaultProps: DefaultProps = {
257
- color: "default",
258
- kind: "primary",
259
- light: false,
260
- size: "medium",
261
- disabled: false,
262
- spinner: false,
263
- };
264
-
265
- renderClickableBehavior(router: any): React.Node {
266
- const {
267
- href = undefined,
268
- type = undefined,
269
- children,
270
- skipClientNav,
271
- spinner,
272
- disabled,
273
- onClick,
274
- beforeNav = undefined,
275
- safeWithNav = undefined,
276
- tabIndex,
277
- target,
278
- rel,
279
- ...sharedButtonCoreProps
280
- } = this.props;
281
-
282
- const ClickableBehavior = getClickableBehavior(
283
- href,
284
- skipClientNav,
285
- router,
286
- );
287
-
288
- const renderProp = (state, {...restChildProps}) => {
289
- return (
290
- <ButtonCore
291
- {...sharedButtonCoreProps}
292
- {...state}
293
- {...restChildProps}
294
- disabled={disabled}
295
- spinner={spinner || state.waiting}
296
- skipClientNav={skipClientNav}
297
- href={href}
298
- target={target}
299
- type={type}
300
- tabIndex={tabIndex}
301
- >
302
- {children}
303
- </ButtonCore>
304
- );
305
- };
306
-
307
- if (beforeNav) {
308
- return (
309
- <ClickableBehavior
310
- disabled={spinner || disabled}
311
- href={href}
312
- role="button"
313
- type={type}
314
- onClick={onClick}
315
- beforeNav={beforeNav}
316
- safeWithNav={safeWithNav}
317
- rel={rel}
318
- >
319
- {renderProp}
320
- </ClickableBehavior>
321
- );
322
- } else {
323
- return (
324
- <ClickableBehavior
325
- disabled={spinner || disabled}
326
- href={href}
327
- role="button"
328
- type={type}
329
- onClick={onClick}
330
- safeWithNav={safeWithNav}
331
- target={target}
332
- rel={rel}
333
- >
334
- {renderProp}
335
- </ClickableBehavior>
336
- );
337
- }
338
- }
339
-
340
- render(): React.Node {
341
- return (
342
- <__RouterContext.Consumer>
343
- {(router) => this.renderClickableBehavior(router)}
344
- </__RouterContext.Consumer>
345
- );
346
- }
347
- }