@khanacademy/wonder-blocks-clickable 2.4.5 → 2.4.7

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 (30) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/components/clickable-behavior.d.ts +248 -0
  3. package/dist/components/clickable-behavior.js.flow +296 -0
  4. package/dist/components/clickable.d.ts +150 -0
  5. package/dist/components/clickable.js.flow +176 -0
  6. package/dist/es/index.js +147 -147
  7. package/dist/index.d.ts +7 -0
  8. package/dist/index.js +169 -171
  9. package/dist/index.js.flow +18 -2
  10. package/dist/util/get-clickable-behavior.d.ts +25 -0
  11. package/dist/util/get-clickable-behavior.js.flow +19 -0
  12. package/dist/util/is-client-side-url.d.ts +7 -0
  13. package/dist/util/is-client-side-url.js.flow +14 -0
  14. package/package.json +5 -5
  15. package/src/components/__tests__/{clickable-behavior.test.js → clickable-behavior.test.tsx} +138 -82
  16. package/src/components/__tests__/{clickable.test.js → clickable.test.tsx} +27 -26
  17. package/src/components/{clickable-behavior.js → clickable-behavior.ts} +63 -78
  18. package/src/components/{clickable.js → clickable.tsx} +107 -124
  19. package/src/{index.js → index.ts} +0 -1
  20. package/src/util/__tests__/{get-clickable-behavior.test.js → get-clickable-behavior.test.tsx} +0 -1
  21. package/src/util/__tests__/{is-client-side-url.js.test.js → is-client-side-url.js.test.ts} +2 -3
  22. package/src/util/{get-clickable-behavior.js → get-clickable-behavior.ts} +9 -3
  23. package/src/util/{is-client-side-url.js → is-client-side-url.ts} +0 -1
  24. package/tsconfig.json +12 -0
  25. package/tsconfig.tsbuildinfo +1 -0
  26. package/src/components/__docs__/accessibility.stories.mdx +0 -152
  27. package/src/components/__docs__/clickable-behavior.argtypes.js +0 -64
  28. package/src/components/__docs__/clickable-behavior.stories.js +0 -178
  29. package/src/components/__docs__/clickable.argtypes.js +0 -237
  30. package/src/components/__docs__/clickable.stories.js +0 -307
package/dist/es/index.js CHANGED
@@ -1,5 +1,3 @@
1
- import _objectWithoutPropertiesLoose from '@babel/runtime/helpers/objectWithoutPropertiesLoose';
2
- import _extends from '@babel/runtime/helpers/extends';
3
1
  import * as React from 'react';
4
2
  import { StyleSheet } from 'aphrodite';
5
3
  import { withRouter, Link } from 'react-router-dom';
@@ -7,6 +5,48 @@ import { __RouterContext } from 'react-router';
7
5
  import { addStyle } from '@khanacademy/wonder-blocks-core';
8
6
  import Color from '@khanacademy/wonder-blocks-color';
9
7
 
8
+ function _objectWithoutPropertiesLoose(source, excluded) {
9
+ if (source == null) return {};
10
+ var target = {};
11
+ var sourceKeys = Object.keys(source);
12
+ var key, i;
13
+ for (i = 0; i < sourceKeys.length; i++) {
14
+ key = sourceKeys[i];
15
+ if (excluded.indexOf(key) >= 0) continue;
16
+ target[key] = source[key];
17
+ }
18
+ return target;
19
+ }
20
+
21
+ function _extends() {
22
+ _extends = Object.assign ? Object.assign.bind() : function (target) {
23
+ for (var i = 1; i < arguments.length; i++) {
24
+ var source = arguments[i];
25
+ for (var key in source) {
26
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
27
+ target[key] = source[key];
28
+ }
29
+ }
30
+ }
31
+ return target;
32
+ };
33
+ return _extends.apply(this, arguments);
34
+ }
35
+
36
+ function _setPrototypeOf(o, p) {
37
+ _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) {
38
+ o.__proto__ = p;
39
+ return o;
40
+ };
41
+ return _setPrototypeOf(o, p);
42
+ }
43
+
44
+ function _inheritsLoose(subClass, superClass) {
45
+ subClass.prototype = Object.create(superClass.prototype);
46
+ subClass.prototype.constructor = subClass;
47
+ _setPrototypeOf(subClass, superClass);
48
+ }
49
+
10
50
  const getAppropriateTriggersForRole = role => {
11
51
  switch (role) {
12
52
  case "link":
@@ -14,7 +54,6 @@ const getAppropriateTriggersForRole = role => {
14
54
  triggerOnEnter: true,
15
55
  triggerOnSpace: false
16
56
  };
17
-
18
57
  case "checkbox":
19
58
  case "radio":
20
59
  case "listbox":
@@ -22,7 +61,6 @@ const getAppropriateTriggersForRole = role => {
22
61
  triggerOnEnter: false,
23
62
  triggerOnSpace: true
24
63
  };
25
-
26
64
  case "button":
27
65
  case "menuitem":
28
66
  case "menu":
@@ -34,7 +72,6 @@ const getAppropriateTriggersForRole = role => {
34
72
  };
35
73
  }
36
74
  };
37
-
38
75
  const disabledHandlers = {
39
76
  onClick: () => void 0,
40
77
  onMouseEnter: () => void 0,
@@ -57,8 +94,9 @@ const startState = {
57
94
  pressed: false,
58
95
  waiting: false
59
96
  };
60
- class ClickableBehavior extends React.Component {
61
- static getDerivedStateFromProps(props, state) {
97
+ let ClickableBehavior = function (_React$Component) {
98
+ _inheritsLoose(ClickableBehavior, _React$Component);
99
+ ClickableBehavior.getDerivedStateFromProps = function getDerivedStateFromProps(props, state) {
62
100
  if (props.disabled) {
63
101
  return _extends({}, startState, {
64
102
  focused: state.focused
@@ -66,152 +104,133 @@ class ClickableBehavior extends React.Component {
66
104
  } else {
67
105
  return null;
68
106
  }
69
- }
70
-
71
- constructor(props) {
72
- super(props);
73
-
74
- this.handleClick = e => {
107
+ };
108
+ function ClickableBehavior(props) {
109
+ var _this;
110
+ _this = _React$Component.call(this, props) || this;
111
+ _this.waitingForClick = void 0;
112
+ _this.enterClick = void 0;
113
+ _this.handleClick = e => {
75
114
  const {
76
115
  onClick = undefined,
77
116
  beforeNav = undefined,
78
117
  safeWithNav = undefined
79
- } = this.props;
80
-
81
- if (this.enterClick) {
118
+ } = _this.props;
119
+ if (_this.enterClick) {
82
120
  return;
83
121
  }
84
-
85
122
  if (onClick || beforeNav || safeWithNav) {
86
- this.waitingForClick = false;
123
+ _this.waitingForClick = false;
87
124
  }
88
-
89
- this.runCallbackAndMaybeNavigate(e);
125
+ _this.runCallbackAndMaybeNavigate(e);
90
126
  };
91
-
92
- this.handleMouseEnter = e => {
93
- if (!this.waitingForClick) {
94
- this.setState({
127
+ _this.handleMouseEnter = e => {
128
+ if (!_this.waitingForClick) {
129
+ _this.setState({
95
130
  hovered: true
96
131
  });
97
132
  }
98
133
  };
99
-
100
- this.handleMouseLeave = () => {
101
- if (!this.waitingForClick) {
102
- this.setState({
134
+ _this.handleMouseLeave = () => {
135
+ if (!_this.waitingForClick) {
136
+ _this.setState({
103
137
  hovered: false,
104
138
  pressed: false,
105
139
  focused: false
106
140
  });
107
141
  }
108
142
  };
109
-
110
- this.handleMouseDown = () => {
111
- this.setState({
143
+ _this.handleMouseDown = () => {
144
+ _this.setState({
112
145
  pressed: true
113
146
  });
114
147
  };
115
-
116
- this.handleMouseUp = e => {
117
- this.setState({
148
+ _this.handleMouseUp = e => {
149
+ _this.setState({
118
150
  pressed: false,
119
151
  focused: false
120
152
  });
121
153
  };
122
-
123
- this.handleTouchStart = () => {
124
- this.setState({
154
+ _this.handleTouchStart = () => {
155
+ _this.setState({
125
156
  pressed: true
126
157
  });
127
158
  };
128
-
129
- this.handleTouchEnd = () => {
130
- this.setState({
159
+ _this.handleTouchEnd = () => {
160
+ _this.setState({
131
161
  pressed: false
132
162
  });
133
- this.waitingForClick = true;
163
+ _this.waitingForClick = true;
134
164
  };
135
-
136
- this.handleTouchCancel = () => {
137
- this.setState({
165
+ _this.handleTouchCancel = () => {
166
+ _this.setState({
138
167
  pressed: false
139
168
  });
140
- this.waitingForClick = true;
169
+ _this.waitingForClick = true;
141
170
  };
142
-
143
- this.handleKeyDown = e => {
171
+ _this.handleKeyDown = e => {
144
172
  const {
145
173
  onKeyDown,
146
174
  role
147
- } = this.props;
148
-
175
+ } = _this.props;
149
176
  if (onKeyDown) {
150
177
  onKeyDown(e);
151
178
  }
152
-
153
179
  const keyCode = e.which || e.keyCode;
154
180
  const {
155
181
  triggerOnEnter,
156
182
  triggerOnSpace
157
183
  } = getAppropriateTriggersForRole(role);
158
-
159
184
  if (triggerOnEnter && keyCode === keyCodes.enter || triggerOnSpace && keyCode === keyCodes.space) {
160
185
  e.preventDefault();
161
- this.setState({
186
+ _this.setState({
162
187
  pressed: true
163
188
  });
164
189
  } else if (!triggerOnEnter && keyCode === keyCodes.enter) {
165
- this.enterClick = true;
190
+ _this.enterClick = true;
166
191
  }
167
192
  };
168
-
169
- this.handleKeyUp = e => {
193
+ _this.handleKeyUp = e => {
170
194
  const {
171
195
  onKeyUp,
172
196
  role
173
- } = this.props;
174
-
197
+ } = _this.props;
175
198
  if (onKeyUp) {
176
199
  onKeyUp(e);
177
200
  }
178
-
179
201
  const keyCode = e.which || e.keyCode;
180
202
  const {
181
203
  triggerOnEnter,
182
204
  triggerOnSpace
183
205
  } = getAppropriateTriggersForRole(role);
184
-
185
206
  if (triggerOnEnter && keyCode === keyCodes.enter || triggerOnSpace && keyCode === keyCodes.space) {
186
- this.setState({
207
+ _this.setState({
187
208
  pressed: false,
188
209
  focused: true
189
210
  });
190
- this.runCallbackAndMaybeNavigate(e);
211
+ _this.runCallbackAndMaybeNavigate(e);
191
212
  } else if (!triggerOnEnter && keyCode === keyCodes.enter) {
192
- this.enterClick = false;
213
+ _this.enterClick = false;
193
214
  }
194
215
  };
195
-
196
- this.handleFocus = e => {
197
- this.setState({
216
+ _this.handleFocus = e => {
217
+ _this.setState({
198
218
  focused: true
199
219
  });
200
220
  };
201
-
202
- this.handleBlur = e => {
203
- this.setState({
221
+ _this.handleBlur = e => {
222
+ _this.setState({
204
223
  focused: false,
205
224
  pressed: false
206
225
  });
207
226
  };
208
-
209
- this.state = startState;
210
- this.waitingForClick = false;
211
- this.enterClick = false;
227
+ _this.state = startState;
228
+ _this.waitingForClick = false;
229
+ _this.enterClick = false;
230
+ return _this;
212
231
  }
213
-
214
- navigateOrReset(shouldNavigate) {
232
+ var _proto = ClickableBehavior.prototype;
233
+ _proto.navigateOrReset = function navigateOrReset(shouldNavigate) {
215
234
  if (shouldNavigate) {
216
235
  const {
217
236
  history,
@@ -219,7 +238,6 @@ class ClickableBehavior extends React.Component {
219
238
  skipClientNav,
220
239
  target = undefined
221
240
  } = this.props;
222
-
223
241
  if (href) {
224
242
  if (target === "_blank") {
225
243
  window.open(href, "_blank");
@@ -240,14 +258,12 @@ class ClickableBehavior extends React.Component {
240
258
  waiting: false
241
259
  });
242
260
  }
243
- }
244
-
245
- handleSafeWithNav(safeWithNav, shouldNavigate) {
261
+ };
262
+ _proto.handleSafeWithNav = function handleSafeWithNav(safeWithNav, shouldNavigate) {
246
263
  const {
247
264
  skipClientNav,
248
265
  history
249
266
  } = this.props;
250
-
251
267
  if (history && !skipClientNav || this.props.target === "_blank") {
252
268
  safeWithNav();
253
269
  this.navigateOrReset(shouldNavigate);
@@ -258,22 +274,19 @@ class ClickableBehavior extends React.Component {
258
274
  waiting: true
259
275
  });
260
276
  }
261
-
262
277
  return safeWithNav().then(() => {
263
278
  if (!this.state.waiting) {
264
279
  this.setState({
265
280
  waiting: true
266
281
  });
267
282
  }
268
-
269
283
  return;
270
284
  }).catch(error => {}).finally(() => {
271
285
  this.navigateOrReset(shouldNavigate);
272
286
  });
273
287
  }
274
- }
275
-
276
- runCallbackAndMaybeNavigate(e) {
288
+ };
289
+ _proto.runCallbackAndMaybeNavigate = function runCallbackAndMaybeNavigate(e) {
277
290
  const {
278
291
  onClick = undefined,
279
292
  beforeNav = undefined,
@@ -283,21 +296,16 @@ class ClickableBehavior extends React.Component {
283
296
  } = this.props;
284
297
  let shouldNavigate = true;
285
298
  let canSubmit = true;
286
-
287
299
  if (onClick) {
288
300
  onClick(e);
289
301
  }
290
-
291
302
  if (e.defaultPrevented) {
292
303
  shouldNavigate = false;
293
304
  canSubmit = false;
294
305
  }
295
-
296
306
  e.preventDefault();
297
-
298
307
  if (!href && type === "submit" && canSubmit) {
299
308
  let target = e.currentTarget;
300
-
301
309
  while (target) {
302
310
  if (target instanceof window.HTMLFormElement) {
303
311
  const event = new window.Event("submit", {
@@ -306,11 +314,9 @@ class ClickableBehavior extends React.Component {
306
314
  target.dispatchEvent(event);
307
315
  break;
308
316
  }
309
-
310
317
  target = target.parentElement;
311
318
  }
312
319
  }
313
-
314
320
  if (beforeNav) {
315
321
  this.setState({
316
322
  waiting: true
@@ -327,9 +333,8 @@ class ClickableBehavior extends React.Component {
327
333
  } else {
328
334
  this.navigateOrReset(shouldNavigate);
329
335
  }
330
- }
331
-
332
- render() {
336
+ };
337
+ _proto.render = function render() {
333
338
  const childrenProps = this.props.disabled ? _extends({}, disabledHandlers, {
334
339
  onFocus: this.handleFocus,
335
340
  onBlur: this.handleBlur,
@@ -354,9 +359,9 @@ class ClickableBehavior extends React.Component {
354
359
  children
355
360
  } = this.props;
356
361
  return children && children(this.state, childrenProps);
357
- }
358
-
359
- }
362
+ };
363
+ return ClickableBehavior;
364
+ }(React.Component);
360
365
  ClickableBehavior.defaultProps = {
361
366
  disabled: false
362
367
  };
@@ -365,7 +370,6 @@ const isClientSideUrl = href => {
365
370
  if (typeof href !== "string") {
366
371
  return false;
367
372
  }
368
-
369
373
  return !/^(https?:)?\/\//i.test(href) && !/^([^#]*#[\w-]*|[\w\-.]+:)/.test(href);
370
374
  };
371
375
 
@@ -374,7 +378,6 @@ function getClickableBehavior(href, skipClientNav, router) {
374
378
  if (router && skipClientNav !== true && href && isClientSideUrl(href)) {
375
379
  return ClickableBehaviorWithRouter;
376
380
  }
377
-
378
381
  return ClickableBehavior;
379
382
  }
380
383
 
@@ -382,60 +385,58 @@ const _excluded = ["href", "onClick", "skipClientNav", "beforeNav", "safeWithNav
382
385
  const StyledAnchor = addStyle("a");
383
386
  const StyledButton = addStyle("button");
384
387
  const StyledLink = addStyle(Link);
385
- class Clickable extends React.Component {
386
- constructor(...args) {
387
- super(...args);
388
-
389
- this.getCorrectTag = (clickableState, router, commonProps) => {
390
- const activeHref = this.props.href && !this.props.disabled;
391
- const useClient = router && !this.props.skipClientNav && isClientSideUrl(this.props.href || "");
392
-
393
- if (activeHref && useClient && this.props.href) {
388
+ let Clickable = function (_React$Component) {
389
+ _inheritsLoose(Clickable, _React$Component);
390
+ function Clickable(...args) {
391
+ var _this;
392
+ _this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this;
393
+ _this.getCorrectTag = (clickableState, router, commonProps) => {
394
+ const activeHref = _this.props.href && !_this.props.disabled;
395
+ const useClient = router && !_this.props.skipClientNav && isClientSideUrl(_this.props.href || "");
396
+ if (activeHref && useClient && _this.props.href) {
394
397
  return React.createElement(StyledLink, _extends({}, commonProps, {
395
- to: this.props.href,
396
- role: this.props.role,
397
- target: this.props.target || undefined,
398
- "aria-disabled": this.props.disabled ? "true" : undefined
399
- }), this.props.children(clickableState));
398
+ to: _this.props.href,
399
+ role: _this.props.role,
400
+ target: _this.props.target || undefined,
401
+ "aria-disabled": _this.props.disabled ? "true" : undefined
402
+ }), _this.props.children(clickableState));
400
403
  } else if (activeHref && !useClient) {
401
404
  return React.createElement(StyledAnchor, _extends({}, commonProps, {
402
- href: this.props.href,
403
- role: this.props.role,
404
- target: this.props.target || undefined,
405
- "aria-disabled": this.props.disabled ? "true" : undefined
406
- }), this.props.children(clickableState));
405
+ href: _this.props.href,
406
+ role: _this.props.role,
407
+ target: _this.props.target || undefined,
408
+ "aria-disabled": _this.props.disabled ? "true" : undefined
409
+ }), _this.props.children(clickableState));
407
410
  } else {
408
411
  return React.createElement(StyledButton, _extends({}, commonProps, {
409
412
  type: "button",
410
- "aria-disabled": this.props.disabled
411
- }), this.props.children(clickableState));
413
+ "aria-disabled": _this.props.disabled
414
+ }), _this.props.children(clickableState));
412
415
  }
413
416
  };
417
+ return _this;
414
418
  }
415
-
416
- renderClickableBehavior(router) {
419
+ var _proto = Clickable.prototype;
420
+ _proto.renderClickableBehavior = function renderClickableBehavior(router) {
417
421
  const _this$props = this.props,
418
- {
419
- href,
420
- onClick,
421
- skipClientNav,
422
- beforeNav = undefined,
423
- safeWithNav = undefined,
424
- style,
425
- target = undefined,
426
- testId,
427
- onKeyDown,
428
- onKeyUp,
429
- hideDefaultFocusRing,
430
- light,
431
- disabled
432
- } = _this$props,
433
- restProps = _objectWithoutPropertiesLoose(_this$props, _excluded);
434
-
422
+ {
423
+ href,
424
+ onClick,
425
+ skipClientNav,
426
+ beforeNav = undefined,
427
+ safeWithNav = undefined,
428
+ style,
429
+ target = undefined,
430
+ testId,
431
+ onKeyDown,
432
+ onKeyUp,
433
+ hideDefaultFocusRing,
434
+ light,
435
+ disabled
436
+ } = _this$props,
437
+ restProps = _objectWithoutPropertiesLoose(_this$props, _excluded);
435
438
  const ClickableBehavior = getClickableBehavior(href, skipClientNav, router);
436
-
437
439
  const getStyle = state => [styles.reset, styles.link, !hideDefaultFocusRing && state.focused && (light ? styles.focusedLight : styles.focused), disabled && styles.disabled, style];
438
-
439
440
  if (beforeNav) {
440
441
  return React.createElement(ClickableBehavior, {
441
442
  href: href,
@@ -463,13 +464,12 @@ class Clickable extends React.Component {
463
464
  style: getStyle(state)
464
465
  }, childrenProps)));
465
466
  }
466
- }
467
-
468
- render() {
467
+ };
468
+ _proto.render = function render() {
469
469
  return React.createElement(__RouterContext.Consumer, null, router => this.renderClickableBehavior(router));
470
- }
471
-
472
- }
470
+ };
471
+ return Clickable;
472
+ }(React.Component);
473
473
  Clickable.defaultProps = {
474
474
  light: false,
475
475
  disabled: false
@@ -0,0 +1,7 @@
1
+ import type { ChildrenProps, ClickableState, ClickableRole } from "./components/clickable-behavior";
2
+ import Clickable from "./components/clickable";
3
+ export { default as ClickableBehavior } from "./components/clickable-behavior";
4
+ export { default as getClickableBehavior } from "./util/get-clickable-behavior";
5
+ export { isClientSideUrl } from "./util/is-client-side-url";
6
+ export { Clickable as default };
7
+ export type { ChildrenProps, ClickableState, ClickableRole };